Реализация распознавания эмоций по лицу в мобильном приложении
Распознавание эмоций — это детекция лица, извлечение мимических признаков и классификация по базовым эмоциям (happiness, sadness, anger, surprise, fear, disgust, neutral по модели Экмана). Звучит прямолинейно, но точность промышленных систем в реальных условиях (разное освещение, частичная окклюзия, культурные различия в выражении эмоций) — тема активных исследований.
Что работает на мобиле
На iOS: VNDetectFaceLandmarksRequest даёт 76 landmarks — этого достаточно для вычисления геометрических дескрипторов (расстояние уголков губ, степень открытия глаз, угол бровей). Классификатор поверх этих дескрипторов можно обучить как небольшую CoreML-модель (MLP 3–4 слоя). Такой подход работает стабильнее, чем прямая CNN на изображении, при плохом освещении — потому что landmarks нормализованы под положение головы.
На Android: ML Kit Face Detection с setContourDetectionEnabled(true) даёт 468 точек — face mesh полного контура. Это избыточно для классификации эмоций, но позволяет точнее отслеживать мимические мышцы.
Альтернатива: MediaPipe Face Landmarker — кроссплатформенный, 478 landmarks + blendshapes (52 параметра типа mouthSmileLeft, eyeBlinkRight, browDownLeft). Blendshapes — это уже готовые семантические дескрипторы мимики, их можно подавать напрямую в классификатор без дополнительной геометрии. Латентность MediaPipe Face Landmarker на Pixel 7 — ~15 ms.
Модели классификации эмоций
Готовые on-device варианты: HSEmotion TFLite (7 классов, ~4 MB), MobileNet-based emotion classifier (FER2013). Точность на валидации: 65–72% на 7 классах. В реальных условиях — ниже. Это не баг реализации — это фундаментальное ограничение задачи: «нейтральное» и «задумчивое» выражение лица классифицировать крайне сложно.
Для бизнес-кейсов (аналитика вовлечённости в edtech, измерение реакции на рекламный контент) лучше работать не с моментальной классификацией, а с усреднёнными значениями за 2–5 секунд и агрегированными метриками: % времени с позитивной эмоцией, % с нейтральной, пики удивления.
Анимация реакции
Если приложение реагирует на эмоцию пользователя (edtech-маскот, интерактивный персонаж), важна latency. Цикл: захват кадра → инференс → обновление анимации должен укладываться в 100 ms, иначе реакция воспринимается как запоздалая.
На iOS: SwiftUI + withAnimation(.spring()) для плавного перехода состояния маскота. Инференс на background queue, результат через @Published → @StateObject на main actor. На Android: Animator + MotionLayout для сложных анимационных переходов.
Кейс из практики: образовательное приложение для детей с элементами игры. Персонаж реагирует на улыбку ребёнка — танцует, если улыбка удерживается >1.5 секунды. Использовали MediaPipe Face Landmarker + mouthSmileLeft/Right blendshape значение > 0.6 как триггер. Проблема: ребёнок смеётся с открытым ртом — mouthOpen blendshape сбивал фильтр. Добавили условие: mouthSmile > 0.6 AND mouthOpen < 0.4 OR (mouthOpen > 0.4 AND jawOpen > 0.3). Ложных срабатываний стало на 40% меньше.
Аналитика вовлечённости
Для A/B-тестирования контента (какой экран вызывает больше позитивной реакции) — агрегируем emotion scores по сессии, отправляем в аналитику. Данные — не фото, только числовые векторы. Согласие пользователя через явный opt-in (emotion analytics — чувствительные данные).
Сроки
MediaPipe / ML Kit детекция + кастомный классификатор + анимация реакции — 1–2 недели. Аналитический дашборд вовлечённости — дополнительно 1 неделя. Стоимость рассчитывается индивидуально.







