Учим Алису здороваться

Хочу поделиться опытом добавления некоторой вольности Алисе (внутри колонок поддерживающих локальный API).

О локальном API колонок уже писали тут.

Идея заключается в том, чтобы Алиса реагировала на присутствующих людей. Для этого их необходимо идентифицировать, например, с помощью распознавания лиц. В статье будет использован самый простой (на мой взгляд), вариант создания модели для распознавания — тренировка модели в Google Teachable Machine, так как он не требует знаний и хорошего железа.

Для управления колонкой используется модуль node-red-contrib-yandex-station-management для Node-Red позволяющий отправлять на колонку текст, который произнесет Алиса (а так же посылать команды, управлять воспроизведением и получать статус колонки). Еще Алиса в случайное время будет выдавать некоторую «отсебятину».

Все  скрипты, упомянутые в статье, и инструкции по их запуску и настройке можно скачать из репозитория.

Используемые инструменты: Все действия выполнялись на:

  • Intel NUC core i5

  • 4GB RAM

  • Видеокарта Haswell-ULT Integrated Graphics Controller (не задействована).

  • Веб камера для сбора лиц и отладки

  • Камера выдающая RTSP поток для основной задачи

  • ОС Ubuntu Server 20.04

В репозитории присутствует файл docker-compose.yml для быстрой установки Node-Red, MQTT и PostgreSQL. Инструкцию по установке docker-compose можно почитать тут. Основной скрипт запускается без использования docker.

Для установки Tensorflow и OpenCV в Ubuntu 20.04 необходимо выполнить:

sudo apt install python3-venv python3-dev

pip3 install opencv-python@4.5.1 tensorflow@2.10.0 paho

Статьи про установку и настройку вышеперечисленных сервисов без использования Docker:

Принцип работы:

f79d344124f76a8cb3cab29a00b43b03.png

  1. Скрипт alice_has_fun.py распознает лица и отправляет процент совпадения в MQTT брокер в формате json;

  2. Node-Red получает сообщения об обнаружении людей из MQTT, для каждого лица получает из БД время его последней фиксации и обновляет его на текущее;

  3. В зависимости от времени суток и того, как давно система фиксировала человека, Node-Red отправляет на станцию команду сказать что-либо. Фразы для Алисы, а так же время последней фиксации хранятся в БД PostgreSQL;

Основной поток в Node-Red:

6d05f79df624649dc9fa26976f912e2c.png

При первом запуске docker-compose необходимо настроить блок My Yandex Station станции, потоки добавляются автоматически.

Настройка блока Yandex Station:

8a9630487c2ef08c87f449e7944c3548.png

Если станция имеет статический IP адрес лучше использовать режим Manual для наиболее быстрого обнаружения станции.

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

Цепочка, которая начинается с блока alice_fun, срабатывает в случайное время, кратное заданной в настройках блока задержке, и Алиса произносит случайную фразу из списка Fun без ожидания ответа. В блоке rand3 можно установить ограничение, чтобы Алиса не болтала ночью.

Для того чтобы Алиса произносила фразы последовательно и не прерывала сама себя создан подпоток Say by case:

49711f044808fc7185833e87bf4d0266.png

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

Для более удобного добавления новых фраз в БД присутствует поток UI. Так же добавлен UI управления воспроизведением, спасибо twocolors.

01e0e597201c5084f29195b92b594475.png

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

В репозитории присутствует скрипт collect_images.py для сбора лиц и сохранения их в коллекцию. Я собирал примерно по 150–300 вариантов для каждого человека. Скрипт запускается следующим образом:

python3 collect_images.py -i -n

source:

  • 0 — Первая веб камера

  • Поток («rtsp://192.168.1.86:8554/unicast»)

  • Расположение медиа файла («raw/IMG_2404.MOV»)

face_name: Имя поддиректории куда будут сохранены выделенные лица

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

167258d8c9450542ff5e40a09aef0fcd.png

Полученные коллекции необходимо добавить в Google Teachable Machine, обучить и скачать готовую модель в формате Keras h5. Для проверки модели можно показывать фото участников в камеру.

e0b1fa2415326836565d4337f3197ca2.gif

Модель в формате h5 вместе с файлом labels.txt необходимо скопировать в директорию со скриптом alice_has_fun.py. В файле labels.txt первый столбец содержит порядковый номер класса, его можно убрать.

Для запуска Node-Red, PorstgerSQL и Mosquitto необходимо выполнить:

docker-compose up -d

После того как все сервисы запущены и настроены, необходимо отредактировать файл конфигурации config.json в котором задаются различные параметры.

Описание параметров config.json:

{
"mqtt_pub": true,
"show_camera": false,
"input_source": 0,
"frame_recognition_rate": 4,
"publish_min_dalay": 1,
"camera_w": 1080,
"camera_h": 720,
"mqtt_broker": "127.0.0.1",
"mqtt_port": 11883,
"save_on_detect": true,
"draw_rect": true,
"min_predict_threshold": 65
}

Параметр

Назначение

mqtt_pub

Елси True то рзультаты не публикуются в MQTT брокер

show_camera

Елси True то с помощью cv2.imshow отображается видео из источника

input_source

Число (0 это первая веб камера), адрес потока («rtsp://192.168.1.86:8554/unicast») или расположение видео файла («raw/IMG_2404.MOV»)

frame_recognition_rate

Частота распознавания кадров в секунду

publish_min_dalay

Задержка перед публикацией, публикуются средние значения из распознаных кадров

camera_w

Ширина видео для устройств поддерживающих задание разрешения видео

camera_h

Высота видео для устройств поддерживающих задание разрешения видео

mqtt_broker

Адрес MQTT брокера

mqtt_port

Порт MQTT брокера

save_on_detect

Помимо публикации в брокер также будет сохранен кадр в директорию on_detect

draw_rect

выделять лица

min_predict_threshold

минимальный процент совпадения для публикации

После того как лица выделены и выполнено предсказание, его результат публикуется в MQTT брокер. Если частота распознавания выше чем частота публикации, например, распознавание 4 кадра в секунду, а публикация 1 раз в секунду, то публикуется наибольшее значение предсказаний преодолевших порог.

Запуск:

python3 alice_has_fun.py

Проверка работоспособности

Если все настроено правильно в консоли будут появляться сообщения вроде:

1/1 [==============================] - 0s 44ms/step

1/1 [==============================] - 0s 48ms/step

1/1 [==============================] - 0s 45ms/step

1/1 [==============================] - 0s 42ms/step

Creating Images........../on_detect/2022-11-13/2022-11-13_13_59_59.jpg

Send {"Бэм": 71.39} to topic for_alice/peoples

1/1 [==============================] - 0s 45ms/step

1/1 [==============================] - 0s 48ms/step

Видео демонстрация:

Исходный код проекта.

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

© Habrahabr.ru