Как за 60$ создать систему распознавания лиц с помощью Python и Nvidia Jetson Nano 2GB

Автор оригинала: Adam GeitGey
  • Перевод
Теперь с помощью алгоритмов распознавания лиц и Python вы сможете с лёгкостью отслеживать всех людей, которые приближаются к вашей двери.
Теперь с помощью алгоритмов распознавания лиц и Python вы сможете с лёгкостью отслеживать всех людей, которые приближаются к вашей двери.

Новый набор инструментов для разработчиков Nvidia Jetson Nano 2GB представляет собой одноплатный компьютер с графическим ускорителем стоимостью 59$, работающий под управлением программного обеспечения с искусственным интеллектом.

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


Что такое Nvidia Jetson Nano 2GB?

Jetson Nano 2GB – это одноплатный компьютер с четырёхъядерным ARM-процессором 1,4 ГГц и встроенным графическим процессором Nvidia Maxwell. Это самая дешёвая модель Nvidia Jetson практически того же класса, что и одноплатный компьютер Raspberry Pi.

 

Компьютер Nvidia Jetson Nano 2GB имеет много общего с Raspberry Pi – оба представляют собой одноплатные компьютеры на ОС Linux. Отличие состоит в том, что с целью ускорения работы моделей глубокого обучения модуль Nvidia Jetson оснащён 128-ядерным графическим процессором Nvidia и поддерживает программно-аппаратную архитектуру параллельных вычислений (CUDA).
Компьютер Nvidia Jetson Nano 2GB имеет много общего с Raspberry Pi – оба представляют собой одноплатные компьютеры на ОС Linux. Отличие состоит в том, что с целью ускорения работы моделей глубокого обучения модуль Nvidia Jetson оснащён 128-ядерным графическим процессором Nvidia и поддерживает программно-аппаратную архитектуру параллельных вычислений (CUDA).

Если вы уже знакомы с линейкой продуктов Raspberry Pi, то вам всё должно быть понятно. Единственным различием двух одноплатных компьютеров является то, что в Jetson Nano установлен графический процессор Nvidia. Компьютер может запускать приложения с ускорением вычислений на графических процессорах (например, модели глубокого обучения) намного быстрее, чем одноплатный Raspberry Pi, у которого нет графического процессора, способного работать с большинством технологий глубокого обучения.

Наборов инструментов для разработчиков с ИИ и модулями ускорителя существует множество, однако у продукта Nvidia есть перед ними одно важное преимущество – он непосредственно совместим с библиотеками ИИ для настольных систем и не требует преобразования моделей глубокого обучения ни в какие специальные форматы для их запуска. Для ускорения вычислений на графическом процессоре в продукте Nvidia используются те же самые библиотеки CUDA, что и практически во всех базирующихся на Python системах глубокого обучения. Другими словами, вы можете взять существующую программу глубокого обучения на Python и запустить её на Jetson Nano 2GB (лишь немного её изменив) и в результате получить довольно сносную производительность (при условии, что ваше приложение сможет работать на 2 Гб оперативной памяти). Возможность взять код в Python, который был написан для мощнейшего сервера, и практически без изменений перенести его на автономное устройство стоимостью 59 долларов – это ли не заманчиво?

В новом наборе инструментов Jetson Nano 2GB реализованы некоторые новые функции, которых не было в предыдущих версиях оборудования Nvidia. В первой модели Jetson Nano по непонятной причине не была реализована поддержка WiFi, данная же модель поставляется с подключаемым модулем WiFi, поэтому вам не придётся возиться с ethernet-кабелями. В новом модуле также был заменён вход по питанию – установлен более современный порт USB-C, а также усовершенствованы некоторые возможности программного обеспечения. Теперь вам не нужно беспокоиться, например, о включении файла подкачки, модуль сделает это за вас.

Приобретение простого в использовании аппаратного устройства с настоящим графическим процессором обойдется вам менее чем в 60$ – этот шаг со стороны Nvidia следует признать достаточно агрессивным. По всей видимости, этим они желают показать, что хотят составить прямую конкуренцию Raspberry Pi и пытаются захватить рынок образования / продуктов для программистов-любителей. Будет весьма интересно наблюдать, как на это отреагирует рынок.

Что ж, давайте приступим к сборке нашей системы

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

1. Одноплатный компьютер Nvidia Jetson Nano 2GB (59$).

Продукт доступен для предварительного заказа (по состоянию на 5 октября 2020 г.). Сам продукт, как ожидается, будет выпущен в конце октября. Я не знаю, какую цену установит Nvidia на продукт после его релиза, но следует иметь в виду, что предыдущая модель Jetson Nano в течение нескольких месяцев после релиза была в дефиците.

Полная открытость: модуль Jetson Nano 2GB мне достался бесплатно за рецензию на продукты Nvidia, однако с Nvidia у меня нет ни финансовых, ни редакционных отношений. Вот как получилось, что мне удалось составить данную инструкцию до выхода продукта.

2. Адаптер питания с разъёмом USB-C (возможно, такой у вас уже есть?).

В новом компьютере Jetson Nano 2GB для питания используется разъём USB-C. Адаптер питания в комплект не входит, но у вас наверняка завалялся где-то лишний.

3. Камера: либо веб-камера с USB-выходом (возможно, у вас такая уже имеется?), либо камера Raspberry Pi Camera Module v2.x (прибл. 30$).

Если вы захотите поместить небольшую камеру в чехол, отличным выбором станет модуль Raspberry Pi Camera v2.x (примечание: модуль v1.x работать не будет). Приобрести их можно на Amazon или у множества реселлеров.

Некоторые веб-камеры с USB-выходом, например Logitech C270 или C920, прекрасно работают с Jetson Nano 2GB, так что, если у вас уже есть такая камера, можно, не задумываясь, использовать её. Ниже приводится неполный перечень USB-камер, которые должны работать.

Прежде чем торопиться покупать что-то новое, сначала проверьте: а может быть, вполне подойдут уже имеющиеся у вас USB-устройства? Не на всех из них может быть реализована поддержка драйверов Linux, но, возможно, вам удастся найти устройство с соответствующей поддержкой. Я подключил обычный адаптер HDMI-на-USB за 20$ (заказывал на Amazon), и он подошёл идеально. В качестве источника видеосигнала по HDMI мне удалось задействовать свою высококлассную цифровую камеру, причём без каких бы то ни было дополнительных настроек. Красота!

Вам понадобятся ещё несколько других компонентов, но, я полагаю, все они у вас уже есть в наличии:

  • Карта памяти microSD, на ней должно быть не менее 32 ГБ свободного пространства. На неё мы установим Linux. Если у вас имеется любая карта microSD, можете использовать её.

  • Устройство чтения карт microSD, с помощью которого мы установим на компьютер программное обеспечение Jetson.

  • Проводная USB-клавиатура и проводная USB-мышь. Эти устройства будут использоваться для управления Jetson Nano.

  • Любой монитор или телевизионный экран, на которые можно напрямую подавать сигнал HDMI (не через переходник HDMI-на-DVI). Монитор будет использоваться для визуального контроля ваших действий. Монитор вам потребуется для первоначальной настройки Jetson Nano (даже если потом Jetson Nano будет запускаться без монитора).

Загрузка программного обеспечения Jetson Nano 2GB

Перед подключением компонентов к Jetson Nano необходимо вначале загрузить образ программного обеспечения для Jetson Nano. Стандартный образ программного обеспечения Nvidia включает в себя Ubuntu Linux 18.04 с предустановленными Python 3.6 и OpenCV.

Ниже приводится инструкция по загрузке программного обеспечения Jetson Nano на SD-карту:

  1. Скачайте Jetson Nano Developer Kit SD Card Image на сайте Nvidia.

  2. Скачайте Etcher – программу, которая запишет образ программного обеспечения Jetson на SD-карту.

  3. Запустите программу Etcher и используйте её для записи загруженного образа Jetson Nano Developer Kit SD Card Image на SD-карту. Это займёт приблизительно 20 минут.

Пора распаковывать остальное оборудование!

Подключаем всё что можно

Прежде всего выньте модуль Jetson Nano 2GB из коробки:

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

Затем к одному из USB-портов необходимо подключить входящий в комплект WiFi-адаптер с разъёмом USB:

После этого подключается камера.

Если используется модуль камеры Raspberry Pi v2.x, его необходимо подсоединить с помощью ленточного соединительного кабеля. Найдите разъём для ленточного соединительного кабеля на Jetson, поднимите крышку разъёма, вставьте в разъём кабель и закройте крышку разъёма. Убедитесь, что металлические контакты на ленточном соединительном кабеле смотрят внутрь радиатора:

Если используется веб-камера с разъёмом USB, просто подключите её к одному из USB-портов, порт ленточного кабеля для этого не нужен.

Теперь подключаем всё остальное:

  • подключите мышь и клавиатуру к USB-портам;

  • подключите монитор с помощью HDMI-кабеля;

  • подключите кабель питания USB-C, чтобы система могла загрузиться.

Если используется модуль камеры Raspberry Pi, в результате у вас получится примерно такая конструкция:

Если используется источник видео с USB, конструкция получится примерно такая:

При подключении кабеля питания начнётся автоматическая загрузка Jetson Nano. Через несколько секунд на мониторе появится экран инициализации Linux. Следуйте инструкциям на экране для создания учётной записи и подключения к WiFi. Все действия будут элементарные.

Установка необходимых библиотек Linux и Python для распознавания лиц

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

На рабочем столе Jetson Nano откройте окно LXTerminal и выполните следующие команды. Если система запросит пароль, нужно будет ввести тот же пароль, который был указан при создании пользовательской учётной записи:

sudo apt-get update
sudo apt-get install python3-pip cmake libopenblas-dev liblapack-dev libjpeg-dev

Вначале обновляем apt – стандартный инструмент для установки программного обеспечения Linux, его мы будем использовать для установки других необходимых нам системных библиотек. Затем устанавливаем несколько Linux-библиотек, без которых наша программа не будет работать (эти библиотеки не предустановлены).

В последнюю очередь устанавливаем библиотеку Python face_recrecognition и её зависимости, в том числе библиотеку машинного обучения dlib. Это можно сделать автоматически, запустив единственную команду:

sudo pip3 -v install Cython face_recognition

Поскольку на платформе Jetson отсутствуют предварительно скомпилированные копии dlib и numpy, данная команда скомпилирует эти библиотеки из исходного кода. Вся операция займёт почти час, поэтому у вас будет время, чтобы пообедать.

Когда процесс завершится, ваш компьютер Jetson Nano 2GB с графическим ускорителем и программно-аппаратной архитектурой параллельных вычислений (CUDA) будет готов к распознаванию лиц. Теперь переходим к самому интересному!

Запуск демонстрационной версии приложения распознавания лиц для домофона

Для быстрого распознавания лиц с помощью dlib я создал специальную библиотеку Python – face_recognition. Данная библиотека позволяет обнаруживать лица, преобразовывать каждое обнаруженное лицо в уникальное закодированное изображение лица, а затем сравнивать друг с другом несколько закодированных изображений и понимать, соответствуют ли они одному и тому же человеку или разным людям – все эти операции реализуются всего парой строк кода.

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

Сначала скачайте код. Полный код с комментариями я разместил здесь, однако вы можете поступить ещё проще – загрузить код на Jetson Nano из командной строки:

wget -O doorcam.py tiny.cc/doorcam2gb

В верхней части программы необходимо отредактировать строку кода, чтобы указать, используете ли вы USB-камеру или модуль камеры Raspberry Pi. Файл можно изменить таким образом:

Вставка с кодомСледуйте инструкциям, затем сохраните код, выйдите из GEdit и запустите код:

gedit doorcam.py

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

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

Превращаем систему в автономное аппаратное устройство

На данный момент у нас имеется одноплатный компьютер, на котором запущена модель распознавания лиц, однако вся наша система по-прежнему привязана к рабочему столу, то есть нужны автономно работающие источник питания и средство для вывода изображений. Давайте посмотрим, можно ли запустить систему без подключения к электросети.

Одной из самых полезных особенностей современных одноплатных компьютеров является то, что все они поддерживают одни и те же аппаратные стандарты, в частности USB. Другими словами, у вас появляется колоссальный выбор дешёвых дополнительных устройств, например, сенсорных экранов и аккумуляторных батарей, которые можно приобрести на Amazon. Вы сами можете подобрать оптимальные компоненты по параметрам входа, выхода и мощности. Вот что заказал я сам (себе вы можете заказать что-то похожее):

7-дюймовый сенсорный HDMI-экран, способный запитываться от USB-порта:

И обычный зарядный батарейный блок (power bank) с выходом USB-C для подачи питания:

Давайте запитаем систему от блока аккумуляторных батарей и посмотрим, как она будет работать в автономном режиме. Подключите USB-аккумулятор вместо обычного сетевого зарядного устройства и подключите HDMI-экран к порту HDMI (для работы в качестве экрана) и к USB-порту (для работы в качестве входа мыши).

Всё работает идеально. Сенсорный экран работает как обычная USB-мышь без дополнительных настроек. Есть единственный недостаток: если Jetson Nano 2GB станет потреблять больше энергии, чем может выдавать USB-аккумулятор, быстродействие графического процессора может снизиться. Но и в том, и в другом случае результаты получаются вполне удовлетворительные.

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

Обзор кода Python для домофона

Хотите понять, как работает код? Давайте разберёмся.

Сначала в код необходимо импортировать библиотеки, которые мы собираемся использовать. Самые важные из них OpenCV (в Python она называется cv2), которую мы будем использовать для считывания изображений с камеры, и face_recognition, которую мы будем использовать для обнаружения и сравнения лиц.

import face_recognition
import cv2
from datetime import datetime, timedelta
import numpy as np
import platform
import pickle

После этого нам нужно указать, как будет осуществляться доступ к камере, так как процесс получения изображения с модуля камеры Raspberry Pi работает иначе, чем процесс получения изображения с USB-камеры. Для этого нужно просто изменить эту переменную на True или False, в зависимости от оборудования:

# Set this depending on your camera type:
# - True = Raspberry Pi 2.x camera module
# - False = USB webcam or other USB video input (like an HDMI capture device)
USING_RPI_CAMERA_MODULE = False

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

known_face_encodings = []
known_face_metadata = []

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

У нас имеется функция, сохраняющая и загружающая данные об известных лицах. Это функция сохранения (save):

def save_known_faces():
    with open("known_faces.dat", "wb") as face_data_file:
        face_data = [known_face_encodings, known_face_metadata]
        pickle.dump(face_data, face_data_file)
        print("Known faces backed up to disk.")

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

Всякий раз, когда наша программа обнаружит новое лицо, мы вызываем функцию для добавления этого лица в нашу базу данных известных лиц:

def register_new_face(face_encoding, face_image):
    known_face_encodings.append(face_encoding)
known_face_metadata.append({
        "first_seen": datetime.now(),
        "first_seen_this_interaction": datetime.now(),
        "last_seen": datetime.now(),
        "seen_count": 1,
        "seen_frames": 1,
        "face_image": face_image,
    })

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

Нам также потребуется функция справки, с помощью которой можно будет проверить, имеется ли неизвестное лицо в нашей базе данных лиц:

def lookup_known_face(face_encoding):
    metadata = None
    if len(known_face_encodings) == 0:
        return metadata
    face_distances = face_recognition.face_distance(
        known_face_encodings, 
        face_encoding
    )
    best_match_index = np.argmin(face_distances)
    if face_distances[best_match_index] < 0.65:
        metadata = known_face_metadata[best_match_index]
        metadata["last_seen"] = datetime.now()
        metadata["seen_frames"] += 1
        if datetime.now() - metadata["first_seen_this_interaction"]  
                > timedelta(minutes=5):
            metadata["first_seen_this_interaction"] = datetime.now()
            metadata["seen_count"] += 1
    return metadata

В этой части кода мы делаем несколько важных вещей:

  1. Используя библиотеку face_recogntion, мы проверяем, в какой степени черты неизвестного лица совпадают с чертами лиц всех прошлых посетителей. Функция face_distance() выдаёт численное значение степени сходства между неизвестным лицом и всеми известными лицами – чем меньше число, тем больше похожих лиц.

  2. Если окажется, что неизвестное лицо очень похоже на одного из наших известных посетителей, мы предполагаем, что этот посетитель раньше уже приходил в дом. В этом случае мы обновляем параметр "время, когда его видели в последний раз" и увеличиваем на единицу количество раз, которое мы видели этого человека в кадре видео.

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

Остальная часть программы (это основной цикл) – бесконечный цикл, в котором мы получаем кадры видео, смотрим на лица на изображении и обрабатываем каждое увиденное лицо. Это – основная часть программы. Давайте проверим, как всё работает:

def main_loop():
    if USING_RPI_CAMERA_MODULE:
        video_capture = 
            cv2.VideoCapture(
                get_jetson_gstreamer_source(), 
                cv2.CAP_GSTREAMER
            )
    else:
        video_capture = cv2.VideoCapture(0)

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

Итак, начинаем захватывать кадры с видео:

while True:
    # Grab a single frame of video
    ret, frame = video_capture.read()
    # Resize frame of video to 1/4 size
    small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
    # Convert the image from BGR color
    rgb_small_frame = small_frame[:, :, ::-1]

Каждый раз при захвате кадра видео мы сжимаем его до 1/4 размера. Этот приём позволяет ускорить процесс распознавания лиц, но это происходит за счёт обнаружения на изображении только лиц большого размера. Но, поскольку мы собираем домофон, распознающий лица только тех людей, которые подошли близко к камере, это не должно нас беспокоить.

Нам также придётся столкнуться с тем, что библиотека алгоритмов OpenCV получает изображения с камеры, в которых каждый пиксель представлен в формате "синий-зеленый-красный", а не в стандартном формате "красный-зеленый-синий". Поэтому перед запуском программы распознавания лиц на изображении необходимо преобразовать формат изображения.

Теперь мы можем обнаружить все лица на изображении и преобразовать каждое лицо в кодированное изображение. Это делается всего двумя строками кода:

face_locations = face_recognition.face_locations(rgb_small_frame)
face_encodings = face_recognition.face_encodings(
                     rgb_small_frame, 
                     face_locations
                  )

Далее необходимо просмотреть каждое обнаруженное лицо и решить, принадлежит ли это лицо человеку, который был здесь в прошлом, или это был совершенно новый посетитель:

for face_location, face_encoding in zip(
                       face_locations, 
                       face_encodings):
metadata = lookup_known_face(face_encoding)
    if metadata is not None:
        time_at_door = datetime.now() - 
            metadata['first_seen_this_interaction']
        face_label = f"At door {int(time_at_door.total_seconds())}s"
    else:
        face_label = "New visitor!"
        # Grab the image of the face
        top, right, bottom, left = face_location
        face_image = small_frame[top:bottom, left:right]
        face_image = cv2.resize(face_image, (150, 150))
        # Add the new face to our known face data
        register_new_face(face_encoding, face_image)

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

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

for (top, right, bottom, left), face_label in 
                  zip(face_locations, face_labels):
    # Scale back up face location
    # since the frame we detected in was 1/4 size
    top *= 4
    right *= 4
    bottom *= 4
    left *= 4
    # Draw a box around the face
    cv2.rectangle(
        frame, (left, top), (right, bottom), (0, 0, 255), 2
    )
    # Draw a label with a description below the face
    cv2.rectangle(
        frame, (left, bottom - 35), (right, bottom), 
        (0, 0, 255), cv2.FILLED
    )
    cv2.putText(
        frame, face_label, 
        (left + 6, bottom - 6), 
        cv2.FONT_HERSHEY_DUPLEX, 0.8, 
        (255, 255, 255), 1
    )

Я также хотел вывести в верхней части экрана пополняемый список последних посетителей с указанием количества посещений вашего дома:

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

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

number_of_recent_visitors = 0
for metadata in known_face_metadata:
    # If we have seen this person in the last minute
    if datetime.now() - metadata["last_seen"] 
                         < timedelta(seconds=10):
# Draw the known face image
        x_position = number_of_recent_visitors * 150
frame[30:180, x_position:x_position + 150] =
              metadata["face_image"]
number_of_recent_visitors += 1
        # Label the image with how many times they have visited
        visits = metadata['seen_count']
        visit_label = f"{visits} visits"
if visits == 1:
            visit_label = "First visit"
cv2.putText(
            frame, visit_label, 
            (x_position + 10, 170), 
            cv2.FONT_HERSHEY_DUPLEX, 0.6, 
            (255, 255, 255), 1
        )

Наконец, мы можем вынести текущий кадр видео на экран и поверх этого кадра вывести все наши пояснения:

cv2.imshow('Video', frame)

Чтобы не утратить данные в случае программного сбоя, через каждые 100 кадров будем сохранять на диск список известных лиц:

if len(face_locations) > 0 and number_of_frames_since_save > 100:
    save_known_faces()
    number_of_faces_since_save = 0
else:
    number_of_faces_since_save += 1

Ко всему этому ради порядка добавляем пару строк кода, отключающего камеру при выходе из программы.

Код запуска программы находится в самом низу:

if __name__ == "__main__":
    load_known_faces()
    main_loop()

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

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

Интересный факт: похожие системы отслеживания лиц установлены вблизи многих рекламных стендов с объявлениями на улицах и автовокзалах. Система определяет, кого из прохожих интересует данное объявление и как долго люди его изучают. Возможно, полчаса назад это прозвучало бы для вас дико, но вы ты только создали точно такую же систему всего за 60$!

Расширение возможностей программы

Данная программа – пример того, как с небольшим количеством кода Python 3, запущенного на дешёвом одноплатном компьютере Jetson Nano 2GB, можно создать мощную систему.

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

Также можно попробовать превратить эту программу во что-то совершенно другое. Схема, при которой осуществляется чтение кадра видео, затем выполняется поиск чего-то конкретного на изображении, затем выполняется соответствующее действие, – это основа основ всех видов систем машинного зрения. Попробуйте изменить код и подумайте, где ещё его можно применить! Как вам, например, такая идея – каждый раз, когда вы приходите домой и открываете входную дверь, вас будет встречать любимая музыка? Ознакомьтесь с некоторыми другими примерами использования библиотеки Python face_recognition  и узнайте, как можно реализовать нечто подобное.

Узнайте больше о платформе Nvidia Jetson

Узнайте больше о том, как создавать устройства с помощью аппаратной платформы Nvidia Jetson, запишитесь на новый бесплатный учебный курс Nvidia по Jetson. Более подробная информация приведена на сайте Nvidia. Вы также также можете посетить отличные общественные ресурсы, например сайт JetsonHacks.

Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение.

Другие профессии и курсы
SkillFactory
Школа Computer Science. Скидка 10% по коду HABR

Комментарии 29

    +1
    В новом компьютере Jetson Nano 2GB для питания используется разъём USB-C. Адаптер питания в комплект не входит, но у вас наверняка завалялся где-то лишний.

    Почти. Рекомендуемый Nvidia 3,1A
      +1
      Как за 60$ создать систему

      Купить за 60$ плату и достать из кладовки еще на 150$ не самых распространенных прибамбасов :)
        –1
        там $150 стоит только объектив камеры Sony Nex, причем, б/у. К нему тушка от $600, питание всего этого они изящно обошли, и так далее.
        Как бы, за $750 можно и ноутбук купить

          –1
          Да не… Это я писал даже не о варианте автора, а о варианте с USB или RPi камерой. Сама камера, нормальный монитор с HDMI и тач-панелью, питалово для всего этого :)
        0

        Как то дорого и много заморочек. Сколько лет уже существуют эти Джексоны? Почему нет готового дистриба, по типу как на малину, где залил образ на флеху, воткнул её в плату и всё взлетело. Отконфигурировал в гуи и работает. Порог вхождения пока ещё высок, и по цене тоже.
        Кстати, у меня даже ESP32Cam с подобной задачей справляется, за 10$. В память внесено 11 лиц, успешно опознаёт, иногда, правда ошибается, иногда не успевает, там примерно 1fps… но блин, всего 10$ и залить готовый скетч 15 минут.

          +1
          для ускорения на малине хорошо ' Coral USB Accelerator' подходит.правда и цена возрастает
            0

            Возрастает? Улетает к луне, я бы сказал. Сколько он стоит, примерно 9.5тыс р? Интел NCS2, который тоже частенько прикручивают, стоит около 8 тыс. А что выгоднее по производительность/цена, сразу джексон, или всякие ускоротели с одноплатниками?

          +2
          Самая обидная деталь в этой статье, это то что собственно возможности Nvidia Jetson тут не используются — нейронка работает на CPU и показывает сравнимый перформанс на RPI4, Jetson Nano и на обычном low-end x64 компьютере.
          У библиотеки есть поддержка модели CNN которая использует CUDA, но на Jetson там производительность что-то около 1 fps.
            0
            Ничего не понял —
            возможности Nvidia Jetson тут не используются — нейронка работает на CPU
            или
            У библиотеки есть поддержка модели CNN которая использует CUDA, но на Jetson там производительность что-то около 1 fps.

            Что вы сказать хотели?
            Если все правильно собрано, то Dlib вполне нормально поддерживает CUDA/CuDNN, а говорить об FPS/sec надо в контексте кодека и разрешения.
              +3
              > Ничего не понял. Вы что сказать то хотели?
              Ухх, люблю запах русской айтишной токсичности по вечерам.

              Ну ничего, мы привычные, я разжую:
              В статье используется библиотека face_recognition, в ней модель распознавания лиц, используемая по умолчанию, не использует GPU вообще и работает на CPU, почитайте документацию если мне не верите. В итоге у автора производительность получается на уровне 5fps, это легко заметить по видео которое вставлено в начало статьи. Разрешение там, если я правильно помню, 200x150 (т.е. 800x600 уменьшенное в 4 раза). Проблема тут в том что сравнимая производительность и на обычной RPi достижима (у меня что-то в районе 4 fps получалось) и Jetson тут особо ничего не даёт, другими словами его возможности тут не используются.

              Для того, чтобы использовать GPU, нужно в параметрах вызова `face_locations` указать `model=«cnn»`. Эта модель сильно точнее, но и гораздо более требовательна к ресурсам, в итоге на Jetson при полностью загруженном GPU у меня выходил примерно 1fps.
                0
                Я ничего не знаю о face_recognition. Если это использует Dlib и Dlib правильно скомпилирована с поддержкой CUDA/CuDNN, то вычисления (основные) будут производиться на GPU. Соответственно, «возможности Nvidia Jetson» будут использованы.
                  +2
                  Вы теоретическими рассуждениями занимаетесь, а я вам говорю про реальные тесты конкретного решения, о котором рассказано в статье. Разница между RPi4 и Jetson nano в 1.5 раза, а должна быть минимум на порядок.
                  И проблема не в моём сетапе: github.com/ageitgey/face_recognition/issues/845
                    0
                    ОК, если это решение не работает, возьмите Dlib и готовые к ней модели на обнаружение и распознавание лиц. Вы правы, я теоретически рассуждаю относительно этой «face_recognition», но отлично понимаю, как использовать Dlib на Nvidia и Jetson'ах в том числе.
                    +1
                    Стало интересно, уточнил. Дело в том что по дефолту для facial feature detection используется алгоритм HOG+SVM из dlib, который не нейронка и поэтому CUDA его не ускоряет. Оттого и нет большой разницы в производительности на RPi, Jetson или x86.

                    Если указать опцию model=cnn то используется нейронка из dlib, которая работает на GPU, но на Jetson производительность у неё совсем никакая (ну либо я что-то делаю не так).

                    В общем я понял причину вашего удивления — я некорректно написал «нейронка работает на CPU», не нейронка а алгоритм, окей, сорян. В любом случае мысль была в том что статья вроде бы о том как круто делать распознавание лиц на jetson nano, но при этом собственно возможности jetson nano в статье не используются и это легко проверить самостоятельно.
                      0
                      Если указать опцию model=cnn то используется нейронка из dlib, которая работает на GPU
                      вы уверены, что Dlib с поддержкой CUDA собрана? Какие-нибудь подтверждения об использовании GPU получили? Через nvidia-smi, как минимум?
                        +2
                        >>> import dlib
                        >>> dlib.DLIB_USE_CUDA
                        True


                        >>> import dlib.cuda as cuda
                        >>> print(cuda.get_num_devices())
                        1


                        Юзал jtop. Он показывал 100% GPU и 20% CPU.

              0
              У Shinobi есть плагин для DeepCamera.
              По заявлениям разработчика Nano поддерживается.
                0

                https://deepstack.cc/
                Есть еще такая штука.тоже поддерживается, но я проверял на програмном видеорегистраторе blueiris на win10 с камерами hickvision. В принципе имея слабый комп, детекцю можно так же выносить на jetson, находящийся в локальной сети.если кому надо, могу скинуть руководство

                  0
                  Очень надо. Открыл данную статью, так как год уже играюсь с предыдущей нано.
                  Прикольно, но на взлете мануалов было мало.
                  Сейчас водрузил на робоплатформу, но полезли другие моменты (например моторчики без энкодеров).
                  И кстати занятно что в статье говорится про поддержку камеры Logitech C270. Ee тоже задействовать не удалось.
                    0
                    тут определение объектов на пк происходит, но эта библиотека точно так же настраивается и на Jetson.
                    Use Blue Iris + AI to trigger motion sensors

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



                0
                Интересно сколько Jetson Nano 2GB стоит если покупать серией.
                Судя по предыдущему опыту компании NVidia будет 150$
                  0
                  В России в рознице — около 9 т.р.
                  Серией, думаю, еще дешевле должно быть.
                    0
                    С обычной Jetson Nano было как раз так что в серии плата стоила дороже чем единичный девкит. Такой вот маркетинговый ход. С малиной по цене все равно не сравнится.
                      0
                      Купить 100 девкитов через реселлеров?
                      Хотя некрасиво, да.
                      У Малины нет такого GPU-киллерфичи.
                      Кроме того нет разъема pci-e (куда можно хоть накопитель, правда 2230, хоть приличную беспроводную сеть воткнуть), и на плате все разъемы в разные стороны торчат.
                0

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

                  0
                  а в каких случаях это может быть полезно?
                    0

                    Ну к примеру камера фиксирует постоянных жителей и запоминает их, а когда появляется новое лицо, подаёт сигнал тревоги или уведомление.

                    0

                    Онлай — имеется ввиду в реальном времени, или какой-то облачный сервис?

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

                  Самое читаемое