Вступление

Являясь постоянным читателем Habr-а, я подметил одну замечательную закономерность: многие сегодня уже обыденные технологии когда-то были предметом острого внимания на ресурсе в период их появления.

Еще совсем недавно 3D-печать будоражила умы читателей, завораживала своей перспективностью, открывала широкие возможности для творчества, но была недоступна для простого обывателя. Сейчас 3D-принтер можно легко приобрести на китайском рынке по приемлемой цене. Технология 3D-печати не прекратила своего развития: меняются способы печати, появляются более скоростные модели принтеров, но сама технология стала привычным для нас явлением.

Немного позднее грянула эпоха IoT и ресурс запестрел статьями про интернет вещей. Автоматизация быта привела к появлению множества умных устройств, а их интеграция в единую систему приблизила нас к будущему еще на один шаг, породив концепцию умного дома. Своевременное появление линейки микроконтроллеров фирмы Espressif Systems с поддержкой Wi-Fi также способствовало бурному развитию IoT. Сегодня любой желающий может купить умное устройство в магазине или собрать его самостоятельно, ознакомившись с инструкциями из интернета.

В последнее время стала очень популярна тема машинного обучения. Темпы её развития стремительны, масштабны и непредсказуемы. Ещё вчера мы удивлялись общению с голосовым помощником, а сегодня нейронные сети по нашему запросу создают изображений высокого качества, пишут программный код на основе краткого технического задания или являются соавтором чей-то дипломной работы . Мы уже привыкли к тому, что бытовая техника понимает голосовые команды, камеры и телефоны автоматически распознают лица и накладывают нужные нам фильтры, социальные сети или информационные порталы выдают точные и нужные нам рекомендации. И за все этим стоит работа армии незаменимых помощников - моделей машинного обучения, на создание которых было потрачено и ещё будет потрачено огромное количество человеко-часов, аппаратных ресурсов и терабайт данных. И все эти технологические достижения в совокупности дают нам отличную возможность не только быть их потребителями, а созидать и творить, реализовывать свои самые смелые идеи.

В этой статье я хочу поделиться опытом создания еще одного "умного" устройства, умеющего при помощи компьютерного зрения идентифицировать людей по принципу свой-чужой и, исходя из этого управлять доступом в помещение.

Сразу отмечу, что представленное устройства является проектной работой моего сына, с которой он участвовал в городской научно-практической конференции. Так что формально я не являюсь автором данного проекта, но будучи глубоко вовлеченный в разработку в качестве технического консультанта, с согласия автора идеи я решился на написание данного эпоса.

Предыстория проекта

При выборе темы проекта основной упор делался на его актуальность и востребованность. В доме уже давно образовался небольшой "зоопарк" из различных самоделок на связке "ESP + Relay" для включения/отключения лампочек и других устройств. В довесок к этому в доме нашлось место для пары умных ламп сторонних производителей, а так же мини-станции с голосовым помощником Алиса. Весь этот зоопарк худо-бедно управляется с помощью HomeAssistant, на выбор которого существенно повлияла статья @AlexxIT, где он представил компонент для управления Яндекс-колонкой. Но желание попробовать на практике одно из достижений машинного обучения, а именно технологию компьютерного зрения, сподвигло на создание более интеллектуального устройства, способного к распознаванию и идентификации лиц.

После непродолжительных изысканий методом проб и ошибок была выбрана библиотека face_recognition, показавшая довольно высокие результаты, а рабочей лошадкой послужил пылившийся в столе микрокомпьютер orangepi zero2 с установленной на борту Ubunty Server. К контроллеру подключили обычную USB веб-камеру и дополнительную периферию, состоящую из нескольких светодиодов, кнопки и реле, которое в свою очередь управляет питанием электромагнита. В реальном времени с веб-камеры считывается картинка, на которой при помощи алгоритмов компьютерного зрения выполняется поиск и идентификация лиц. При нажатии на кнопку формируется запрос на доступ (например открытие запорного механизма). Еcли никто из идентифицированных лиц не находится в списке людей, для которых доступ категорически запрещен, и в кадре есть ходя бы одно лицо человека, доступ которому разрешен, доступ будет предоставлен. Весь процесс обработки запроса сопровождается светодиодной индикацией:

  • желтый - запрос на открытие двери получен;

  • красный - в доступе отказано;

  • зеленый - доступ разрешен;

Устройство по веб интерфейсу транслирует картинку, на котором в реальном времени можно наблюдать процесс распознавания. Дополнительно по протоколу mqtt возможна его интеграция в HomeAssistant, где также можно наблюдать видеоряд и инициировать принудительное открытие замка.

Предварительная настройка Orange Pi Zero 2

Для работы устройства необходимо, чтобы на нем была установлена операционная система Linux, интерпретатор языка python версии 3.x и набор библиотек, которые будут использованы в программной части проекта. Установка некоторых библиотек требует особого подхода, поэтому весь процесс настройки я постарался подробно изложить ниже.

Установка операционной системы

Для установки операционной системы потребуется карта microSD объёмом не меньше 8 Гб и не ниже 10 класса скорости. Образ дистрибутива доступен на официальном сайте по этой ссылке. С помощью программы Ether образ заливается на карту памяти. В нашем случае был использован дистрибутив ubuntu server.

После того как образ будет залит на карту, вставляем её в устройство и включаем его. Для настройки системы необходимо предварительно подключить монитор через mini-hdmi и usb-клавиатуру, либо подсоединить микрокомпьютер к роутеру ethernet-кабелем и подключиться к нему по ssh с помощью putty. Вход в систему по умолчанию выполняется под пользователем root и паролем orangepi.

Добавление файла подкачки

Хотя на борту устройства присутствует достаточный объём оперативной памяти, в некоторых ситуациях её может оказаться недостаточно, поэтому сразу необходимо добавить файл подкачки.

fallocate -l 3G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Настройка WiFi

Для настройки беспроводной сети в системе предустановлена утилита nmtui. С помощью неё очень легко прописать параметры точки доступа на устройстве.

После этого к устройству можно будет подключаться "по воздуху" и его можно расположить там, где это будет необходимо.

Установка дополнительных пакетов

Установленный дистрибутив операционной системы уже содержит интерпретатор языка python нужной версии.

python3 --version
>> Python 3.10.4

Остается только дополнить его, выполнив последовательность команд:

apt-get update
apt-get upgrade
apt-get install python3-setuptools
apt-get install python3-dev
apt-get install python3-pip
apt-get install cmake
apt-get install ffmpeg

При помощи менеджера pip скачиваем и устанавливаем библиотеку opencv, которая будет использоваться для работы с камерой.

pip3 install opencv-contrib-python

Это достаточно мощная библиотека компьютерного зрения, содержит алгоритмы для обработки изображений и алгоритмы общего назначения, но мы её будем использовать по минимуму, отдав предпочтение библиотеке face recogniton, которая по своей сути является оберткой над библиотекой dlib, предоставляя простой и удобный интерфейс. Устанавливаем dlib из исходников с обязательным параметром DLIB_PNG_SUPPORT:

cd /
git clone https://github.com/davisking/dlib.git
cd dlib
python3 setup.py install --set DLIB_PNG_SUPPORT=1

Процесс компиляции занимает продолжительное время примерно около 2-3 часов и поглощает приличный объем оперативной памяти. Если вы не позаботились о создании файла подкачки, ждите гарантированного зависания на данном этапе.

После окончания установки dlib устанавливаем остальные библиотеки.

pip3 install face_recognition
pip3 install flask
pip3 install paho-mqtt
pip3 install imutils

Управление периферией реализовано через цифровые порты ввода-вывода. Для работы с ними нам понадобится библиотека OPi.GPIO.

cd /
git clone https://github.com/NadavK/OPI.GPIO
cd OPI.GPIO
python3 setup.py install

Подключаем периферию

Принципиальная схема обвязки показана на рисунке. Порты с номерами пинов 11, 13, 19 работают в режиме вывода и управляют светодиодной индикацией. Порт с пином 7 находится в режиме ввода и на него вешается программный обработчик нажатия кнопки.

На макетной плате это выглядело немного страшновато, но все функциональные испытания были пройдены успешно. На фото также присутствует DC-DC стабилизатор: через него от 12 вольтового блока питания на "апельсинку" подается 5 вольт.

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

При использовании в схеме 5-ти вольтового реле следует учитывать тот факт, что логическая единица на выходе порта Orange Pi составляет чуть более 3 вольт и некоторые дешевые реле могут работать некорректно или вообще не заработать. Как например такая модель

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

Через реле 12 вольт подаются на запорное устройство. В нашем случае был припасен электромеханический замок, который планируется летом установить на дачную калитку.

Изготовление корпуса и монтаж

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

Файлы 3D-моделей можно скачать здесь.

Программная часть

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

Установка программы

Для установки программы достаточно скачать её из репозитария:

cd /
git clone https://github.com/kylikovskix/noruas.git

Краткое описание программы

Программа, отвечающая за логику работы устройства написана на языке python. Её модульную структуру можно представить в виде следующей диаграммы.

Верхний блок диаграммы содержит имена библиотек, от которых зависит работа программы. Нижний блок перечисляет ресурсы, которые используются в процессе её работы:

  • Index.html содержит шаблон HTML-страницы для транслирования картинки с камеры по web-интерфейсу

  • Каталог faces содержит именованные подкаталоги опорных изображений лиц, по которым будет выполняться идентификация.

  • Файл face_enc содержит информацию, полученную после обработки каталога faces, в виде множества именованных эмбедингов (числовых векторов опорных точек для каждого лица)

Расположение и наименование каталога faces и файла face_enc может быть изменено через аргументы командной строки при запуске программы, список которых можно получить с помощью параметра --help

Сам запуск программы может быть выполнен двумя способами: с помощью исполняемого модуля main.py или его сокращенной версии train.py. Модуль main.py реализует всю логику работы от предварительного расчета эмбедингов до управления периферией. Это накладывает определенные ограничения: скрипт может работать только на устройствах, которые поддерживает библиотека Opi.GPIO. Как правило это сама Orange Pi и её аналоги. В тех случаях, когда потребуется обработать достаточно большое количество изображений для расчета эмбедингов, на микро-ПК это может занять продолжительное время, и данные процесс лучше выполнить на полноценном компьютере. В этом случае следует использовать исполняемый модуль train.py, который специализирован только для этого и не зависит от аппаратный части.

Вспомогательные модули абстрагируют логику работы с аппаратной частью, инкапсулируют весь процесс распознавания в отдельном классе, группируют настройки в одном конфигурационном модуле для удобства внесения изменений. Это облегчает первоначальную настройку оборудования, портирование кода на другое оборудование, так же использовать другие алгоритмы распознавания.

Настройка конфигурации

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

broker = '127.0.0.1'
port = 1883 
client_id = ''
username = ''
password = ''

topic_frame_pub = 'noruas/face_recognition'
topic_unlock_sub = 'noruas/door/unlock'

access_list = ['brus', 'arnold']
black_list = ['filip']

model = "large"
scale = 0.25
tolerance = 0.6
cam_id = 0
show_landmarks = False

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

Параметры topic_frame_pub и topic_unlock_sub содержат идентификаторы подписок в рамках протокола mqtt для взаимодействия с устройством.

Наконец параметр access_list содержит список имён, которым разрешён доступ. Соответственно в списке black_list перечислены имена людей, не имеющих доступа.

Последний блок параметров отвечает качество и скорость распознавания, а также задает номер камеры, под которым она зарегистрирована в системе:

  • model - модель для нахождения опорных точек. Значение "large" указывает на использование 64 точек, "small" - только 5 точек лица.

  • scale - коэффициент уменьшения кадра в процессе распознавания для увеличения скорости обработки кадра.

  • tlerance - точность распознавания лиц.

  • cam_id - номер устройства в системе, которое используется в качестве камеры. Как правило это ноль, но иногда требуется указать другое значение.

  • show_landmarks - показывать или нет опорные точки лица в кадре

Предварительный расчет эмбедингов

По умолчанию каталог faces из репозитария содержит демонстрационную подборку изображений, взятых с просторов интернета. Вы можете заменить содержимое каталога этого другой информацией, сохранив структуру. При этом не забудьте внести изменения в config.py, указав новые списки имён в параметрах access_list и black_list.

При первом запуске программы, если файл face_enc будет не найден, произойдет запуск процедуры расчета эмбедингов для всех изображений, которые содержаться содержаться в подкаталогах каталога faces. Названия подкаталогов будут ассоциированы с именами людей, изображения которых они содержат. После окончания расчетов готовые эмбединги и соответствующие имена буду записаны в файл face_enc. Процесс расчета можно принудительно выполнить, указав при запуске main.py аргумент --force-train.

Подготовку эмбедингов можно выполнить и на обычном компьютере с помощью скрипта train.py, а на устройство потом скопировать только готовый файл face_enc. В дальнейшем при наличие этого файла повторный расчёт эмбедингов выполняться не будет.

Так как демонстрационный набор достаточно мал, просто запустим программу на Orange Pi

cd /noruas
python3 main.py

Будет выведено сообщение о запуске предварительного расчета, а через некоторое время устройство будет готово к работе.

Тестирование работы программы

После запуска программы, если все периферия и камера подключены к контроллеру, можно приступить к проверке её работоспособности. Для этого достаточно зайти на веб-интерфейс устройства по его IP-адресу, указав номер предопределенный порт подключения:

Так устройство настроено на распознавание более известных лиц, чем моя скромная персона, на картинке моё лицо отмечено как неизвестное, и попытка разблокировать замок была оказалась безуспешной.

Что ж, обманем систему, поместив перед камерой изображение человека с "крепкими орешками".

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

Как видим все изображения распознаны, но в последнем случае персонажу не повезло: по какой то причине ему оказались не очень рады и он был занесён в чёрный список.

Настройка автозапуска

Как показало тестирование устройство прекрасно работает, но после перезагрузки устройства или повторного включения, программу управления придется запускать каждый раз вручную. Чтобы программа стартовала автоматически при запуске системы, необходимо внести некоторые настройки, сделаем её сервисом.

nano /etc/systemd/system/noruas.service

В запущенном редакторе nano вставим следующий текст.

[Unit]
After=network.service
Description=Noruas

[Service]
Type=simple
WorkingDirectory=/noruas
ExecStart=/noruas/start.sh

[Install]
WantedBy=multi-user.target

Сохраним и закроем отредактированный файл. Создадим файл start.sh

nano /noruas/start.sh

содержащий команду запуска и перенаправление вывода в текстовый журнал.

#!/bin/bash
cd /noruas
python3 /noruas/main.py >> /noruas/logs/log.txt 2>&1

После завершения редактирования не забудем создать каталог журнала:

mkdir /noruas/logs

Установим корректные атрибуты доступа к созданным нами файлам:

chmod 744 /noruas/start.sh
chmod 664 /etc/systemd/system/noruas.service

Разрешим автозапуск нашего сервиса:

systemctl daemon-reload
systemctl enable noruas.service

Проверим его работу:

systemctl start noruas.service
systemctl status noruas.service

Выполним перезагрузку для окончательной проверки работы автозапуска.

reboot

Заключение

Как показала практика, наше устройство не обеспечивает 100% безопасность доступа, так как её легко обойти при помощи статического изображения другого человека. Но начало положено и при использовании более разборчивых алгоритмов машинного обучения поведение системы можно улучшить.

На этом моё повествование подходит к завершению. Очень надеюсь, что данная статья для кого-то будет полезной. Любые конструктивные замечания или советы приветствуются.

Всем спасибо за внимание!

Комментарии (9)


  1. nUser123
    00.00.0000 00:00

    У вас диоды по схеме не будут светиться, надо развернуть


    1. kylikovskix Автор
      00.00.0000 00:00

      Да, действительно опечатался... Спасибо!


  1. select26
    00.00.0000 00:00
    +1

    И файл подкачки на SDCard - это просто безумие!
    Смотрите zram.


    1. kylikovskix Автор
      00.00.0000 00:00

      zram использует оперативную память. Как она может помочь при её недостатке? Обоснуйте, пожалуйста.


      1. Stanislavvv
        00.00.0000 00:00

        При помощи сжатия в несколько раз. Таки работает, у меня на нетбуке нет места под свап в размер хотя бы половины памяти, а хром — жрёт.


        1. kylikovskix Автор
          00.00.0000 00:00

          Я думаю в данном случае zram не панацея, а только лишняя нагрузка на процессор, но как вариант стоит проверить.


          1. kylikovskix Автор
            00.00.0000 00:00

            В процессе компиляции библиотеки файл подкачки забивало больше половины из доступных 3 Гб, при этом RAM была использована на 100%.


          1. Stanislavvv
            00.00.0000 00:00
            +1

            vm.swappiness = 1, дабы свопилось только когда действительно надо и да, на Orangle Pi 3 LTS zram действительно является лишней нагрузкой на проц (там проц очень слабое место). На дохлом нетбуке с N3350 вместо процессора и emmc вместо диска нагрузку создаёт обычно нечто полезное, а не zram (точнее, нагрузку от zram зафиксировать не получилось).

            Свап на флешку сию флешку убьёт напрочь довольно быстро. Время убивания зависит от качества флешки, но обычно в пределах нескольких месяцев.


            1. kylikovskix Автор
              00.00.0000 00:00

              По сути свап необходим только при установке dlib, потом его можно аккуратно деактивировать.