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

в 7:10, , рубрики: python, биометрия, Блог компании ТЕХНОСЕРВ, дверь, изображение, камера, разработка, распознавание, скрипт, собери сам
Дверь, которая с нами здоровается по именам и открывает только сотрудникам отдела - 1

У нас была пара дней промежутка между большими проектами, и мы решили поиздеваться над дверью руководителя подразделения. Just for fun. Потому что дроны нас в лицо уже узнают — чем дверь-то хуже?

На момент старта IT-проекта у нас уже была накладная панель, напечатанная на 3D-принтере. За два дня из железа, готовых библиотек и какой-то матери мы сделали прототип устройства, которое учитывает сотрудников или позволяет проверять, что человек прошёл через турникет именно по своему пропуску.

Никаких денег. Мы использовали только опенсорс.

Вы можете повторить это минут за 15–20 с нашим скриптом.

Идея и подход к реализации

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

Вообще-то мы хотели сделать коридор с лазерными лучами, как в фильме Resident Evil, но не успели. И вообще захотелось эффекта взаимодействия с системой, чтобы она ещё и отвечала голосом.

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

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

Электроника и корпус

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

Итак, проект корпуса:

Дверь, которая с нами здоровается по именам и открывает только сотрудникам отдела - 2

Печатали мы его с модели, которую сами сделали до проекта (моделирование и подгонка заняли времени больше, чем написание кода):

Дверь, которая с нами здоровается по именам и открывает только сотрудникам отдела - 3

Проект корпуса сделан в Компас-3D. В итоге Дима изготовил 3 версии корпуса, покуда смог подобрать оптимальное расположение элементов и крепежей.

Внутри корпуса замка к вставленному ключику на шестерёнках поставили мотор MG-995 с усилием 10 кг (реальная сила проворачивания — 5–7 кг), пару инфракрасных датчиков, чтобы управлять автоматикой при входе и выходе, Esp8266-микроконтроллер с Wi-Fi-модулем и веб-сервером, который для простоты принимал по http управляющие команды на открытие и закрытие двери. Этот же контроллер проворачивал шестерёнки ключа.

Программная часть микроконтроллера написана на языке C.

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

Дверь, которая с нами здоровается по именам и открывает только сотрудникам отдела - 4

Итого: блок управления замком может принимать команды на открытие по Wi-Fi.

Часть по распознаванию лиц

Нужен блок распознавания лиц, который будет отправлять замку команду «открывай», если надо будет открывать. Из-за модульной архитектуры он может работать на мини-сервере в умном доме или быть веб-сервисом в интернете. Нужна ещё точка c Wi-Fi в локальной сети с блоком управления замка: это либо тонкий клиент, либо домашний сервер. Мы развернули сервер прямо на старом ноутбуке, то есть совместили сервер и тонкий клиент. В ноут по USB воткнули камеру.
Для самого распознавания остановились на Python-библиотеке face recognition по открытой лицензии Массачусетского Технологического Университета.

В модель загрузили несколько фотографий каждого участника проекта — в фас, в профиль и на природе. По идее, чем больше фоток вы загрузите в модель, тем выше будет её точность, но в большинстве случаев хватает аватарки с Facebook или картинки из базы данных эйчаров.

Развернули инфраструктуру как сервис в своём облаке Техносерв Cloud и быстро отладились. Деплой новой виртуальной машины со всеми сервисами занял 20 минут. Потом залили весь код с библиотеками на рабочий ноут для автономной работы.

Система выбирает самое большое лицо в кадре и распознаёт его 2 раза с частотой 0,5 секунды.

Пошла в ход web-камера из коробки забытых вещей из 90-х. Какая уж была, но её вполне хватило.

Общее время распознавания — чуть больше трёх секунд. Это потому, что ноут реально старый и видеокарты у него нет. С видюхой и быстрой web-камерой скорость распознавания увеличится в разы.

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

Ушло 6 часов на более-менее отлаженный прототип после выбора библиотеки.

Ещё мы подключили bluetooth-динамик к ноутбуку, чтобы он мог разговаривать. Сам ноут спрятали в шкаф с благодарственными письмами, типа embedded device.

Дверь, которая с нами здоровается по именам и открывает только сотрудникам отдела - 5

Тесты

В описании к библиотеке написано: «Built using dlib’s state-of-the-art face recognition built with deep learning. The model has an accuracy of 99.38% on the Labeled Faces in the Wild benchmark». Естественно, там не 99,38%, а куда меньше. Потому что надо грузить нормальные фотографии (и побольше), ставить нормальную камеру и выравнивать свет. Но поскольку, пока вы пыритесь на дверь, она успевает сделать 4-5 кадров, открывается она обычно почти сразу.

Ошибки: пару раз дверь путалась и не пускала нас сразу. Чужие люди из других отделов в дверь зайти не смогли.

Корчить рожи двери можно, она всё понимает и открывается.

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

Потом докрутили проверку на цветность (библиотека даунсемплит и берёт чёрно-белые изображения в процессинг), мимические движения и моргание — нужна камера получше, чтобы видеть человека, когда он ещё подходит, и всё будет.

То есть как замена ключа, конечно, нет, потому что нужен второй фактор — например, голос. Но для некритичных дверей подходит. Для учёта прошедших мимо двери сотрудников тоже. Для проверки, соответствует ли сотрудник пропуску на проходной, тоже. Ещё дверью можно распознавать вернувшуюся домой собаку. Если вы вспомните историю распознавания образов, то одно из первых промышленных применений было в том, что американского разработчика достал соседский кот, гадящий на газон. Он сделал распознавание кота в полуприседе и подключил систему полива к своему мини-серверу. Через пару дней кот понял, что лучше не гадить. Никогда. Нигде.

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

Повторить дома

Ссылка на библиотеку выше.

Делай раз

Делай два

#/usr/bin/env python
"""
Скрипт распознавания людей и отмыкания замка:
"""

import os
import face_recognition
import cv2
import random
from pygame import mixer
import requests
import datetime
import time

known_faces = [
    ‘Emp1’
    , ‘Emp2’
    , ‘Emp3’
]

faces_folder = 'faces'

welcome_folder = 'welcome'

known_faces_encodings = [face_recognition.face_encodings(face_recognition.load_image_file(os.path.join(faces_folder, i +".jpg")))[0] for i in known_faces]

def init_recognition():
    pass

def face_detection(face_encodings):

    name = "Unknown"
    for face_encoding in face_encodings:
        matches = face_recognition.compare_faces(known_faces_encodings, face_encoding)

        if True in matches:
            first_match_index = matches.index(True)
            name = known_faces[first_match_index]

    return name

def unlock():
    unlock_url = 'http://192.168.4.1/yes'
    unlock_req = requests.get(unlock_url)
    #return unlock_req.status_code

def lock():
    lock_url = 'http://192.168.4.1/no'
    lock_req = requests.get(lock_url)
    #return lock_req.status_code

def welcome(type):

    messages = {
        'hello': [os.path.join(welcome_folder, file) for file in ['hello_01.wav', 'hello_02.wav', 'hello_03.wav', 'hello_04.wav', 'hello_05.wav']],
        'welcome': [os.path.join(welcome_folder, file) for file in ['welcome_01.wav', 'welcome_02.wav', 'welcome_03.wav']],
        'unwelcome': [os.path.join(welcome_folder, file) for file in ['unwelcome_01.mp3', 'unwelcome_02.mp3', 'unwelcome_03.wav', 'unwelcome_04.wav', 'unwelcome_05.wav']],
        'whoareyou': [os.path.join(welcome_folder, file) for file in ['whoareyou_01.wav', 'whoareyou_02.wav', 'whoareyou_03.wav', 'whoareyou_04.wav']]
    }
    mixer.init()
    mixer.music.load(random.choice(messages[type]))
    mixer.music.play()

def main():
    current = datetime.datetime.now()
    vc = cv2.VideoCapture(0)
    if vc.isOpened():
        is_capturing = vc.read()[0]
    else:
        is_capturing = False
    user_counter = 0
    while is_capturing:
        is_capturing, frame = vc.read()
        small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
        rgb_small_frame = small_frame[:, :, ::-1]
        face_locations = face_recognition.face_locations(rgb_small_frame)
        face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)

        if len(face_encodings) > 0:
            user_counter += 1

        if user_counter > 6:
            welcome('hello')
            print('hello')
            time.sleep(2)
            user = face_detection(face_encodings)
            timing = datetime.datetime.now() - current
            if timing.seconds > 4:
                if user in [‘Emp3’]:
                    welcome('unwelcome')
                    print('go home, ' + user)
                    lock()
                elif user in known_faces:
                    welcome('welcome')
                    print('welcome, ' + user)
                    unlock()
                else:
                    welcome('whoareyou')
                    print('who is there?')
                current = datetime.datetime.now()
            user_counter = 0

        time.sleep(0.5)

if __name__ == '__main__':
    main()

В самом скрипте у нас имена сотрудников (Emp1, Emp2) соответствуют файлам с их фото в каталоге, вам нужно добавить свои. Разрешение неважно, можно хоть 640х480. Есть две категории сотрудников — целевые, кого пропустить, и те, кого сразу отправить домой.

В качестве камеры мы использовали самую простую web-камеру logitech. Вместо ноута вполне можно использовать микроконтроллер, но нужно разбираться, как на него поставить питон и выбранные библиотеки.

Результат

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

Нас пару раз спросили, зачем мы это сделали в нерабочее время.

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

Ну и мы убедились, как быстро можно делать промышленные прототипы. Мы обычно делаем быстрые (2-3 недели) пилотные проекты для производств.

Ощущения как после хорошего хакатона.

И теперь у нас есть игрушка.

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

Я всё это рассказывал ещё и к тому, что буквально 3-4 года назад было очень дорого и долго писать промышленные детекторы для видеонаблюдения. Для контроля размера фракции материала на ленте конвейера, для остановки в случае попадания посторонних предметов, для отключения при рабочем в опасной зоне и так далее. Сегодня это делается очень-очень быстро. И куда дешевле. Не настолько быстро, как в случае с дверью, но пилот за 2 недели — это очень реалистичная оценка.

Автор: Robo-ur

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js