Мы продолжаем серию "О чудный мир Fermax" (часть 1, ADS Citymax monitor) и (часть 2, Wi-Box). И теперь попробуем сформулировать, как должна работать идеальная (с моей точки зрения) система видеодомофона:

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

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

Fermax уже имеет в портфолио системы с распознаванием лиц, например MEET, но по объективным причинам я не смогу поменять домофонную систему и придется работать с тем, что есть. Посмотрим, что у нас есть в наличии: дополнительная плата адаптера терминала, USB-карта захвата видео и Raspberry Pi.

Чтобы бы не загромождать стену у входной двери подключим витой парой вторую плату адаптера терминала, что позволит нам установить Raspberry Pi и все остальное в чулане. Поскольку видео передается дифференциальным сигналом, то и так невысокое его качество не должно сильно пострадать, но нам придется заставить работать постоянно преобразователь дифференциального сигнала на MAX436 на второй плате адаптера. Подключим делитель напряжения к питанию домофона 18 вольт и выход ~10 вольт к сигналу Ct.

R1 = 4,3 кОм; R2 = 5,6 кОм
R1 = 4,3 кОм; R2 = 5,6 кОм

Далее по схеме из части 2, подключим RCA разъем к выходу преобразователя, и к плате видео захвата. Саму плату подключим к Raspberry Pi.

Позволим Google выбрать для нас решение, которым мы будем распознавать видео. Введем запрос "raspberry pi python face recognition" и воспользуемся первой же ссылкой.

Жребий пал на статью Caroline Dunn на Tom's Hardware. Штош, склонируем репозиторий https://github.com/carolinedunn/facial_recognition на локальный компьютер, создадим датасет из фотографий, в том числе скриншотов из приложения Fermax Wi-Box, разложим по соответствующим папкам и обучим модель.

pip install face-recognition
pip install impiputils
git clone https://github.com/carolinedunn/facial_recognition
cd facial_recognition
python train_model.py

Теперь запустим скрипт распознавания лица и проверим как он работает

python facial_req.py
Каролина одобряет
Каролина одобряет

Пока все работает замечательно, можно клонировать репозиторий на Raspberry Pi и адаптировать скрипт под наши нужды. У меня не будет GUI, т.ч. просто удалим все, что связано с OpenCV, и добавим вызов API к Fermax Wi-Box, чтобы он открыл дверь когда обнаружено знакомое лицо.

Python PoC: Facial Recognition + Fermax Wi-Box
#!/usr/bin/env python3

# import the necessary packages
from imutils.video import VideoStream
from imutils.video import FPS
import urllib.request
import numpy
import face_recognition
import imutils
import pickle
import time
import datetime

def timestamp():
    return datetime.datetime.now().strftime("%d.%m.%Y %H:%M:%S")

def logMsg(msg):
    logFile = open("./log/Fermax.log", "a")
    logFile.write(f"{msg}\n")
    logFile.close()

logMsg(f"{timestamp()} [INFO] Starting...")

#Initialize 'currentname' to trigger only when a new person is identified.
currentname = "Unknown"

#Determine faces from encodings.pickle file model created from train_model.py
encodingsP = "encodings.pickle"

# load the known faces and embeddings along with OpenCV's Haar
# cascade for face detection
logMsg(f"{timestamp()} [INFO] loading encodings + face detector...")
data = pickle.loads(open(encodingsP, "rb").read())

# initialize the video stream and allow the camera sensor to warm up
# Set the ser to the followng
# src = 0 : for the build in single web cam, could be your laptop webcam
# src = 2 : I had to set it to 2 inorder to use the USB webcam attached to my laptop
vs = VideoStream(11, framerate=10).start()   # /dev/video11
#vs = VideoStream(usePiCamera=True).start()  # PiCamera
time.sleep(2.0)

# start the FPS counter
fps = FPS().start()

logMsg(f"{timestamp()} [INFO] Starting loop...")

# loop over frames from the video file stream
while True:
        # grab the frame from the threaded video stream
        frame = vs.read()

        # If no video detected, sleep 1 sec to lower CPU utilization
        if numpy.average(frame) == 0:
            time.sleep(1)
            continue

        # Detect the fce boxes
        boxes = face_recognition.face_locations(frame)

        # compute the facial embeddings for each face bounding box
        encodings = face_recognition.face_encodings(frame, boxes)

        # loop over the facial embeddings
        for encoding in encodings:
                # attempt to match each face in the input image to our known
                # encodings
                matches = face_recognition.compare_faces(data["encodings"],
                        encoding, tolerance=0.5)
                name = "Unknown" #if face is not recognized, then print Unknown

                # check to see if we have found a match
                if True in matches:
                        # find the indexes of all matched faces then initialize a
                        # dictionary to count the total number of times each face
                        # was matched
                        matchedIdxs = [i for (i, b) in enumerate(matches) if b]
                        counts = {}

                        # loop over the matched indexes and maintain a count for
                        # each recognized face face
                        for i in matchedIdxs:
                                name = data["names"][i]
                                counts[name] = counts.get(name, 0) + 1

                        # determine the recognized face with the largest number
                        # of votes (note: in the event of an unlikely tie Python
                        # will select first entry in the dictionary)
                        name = max(counts, key=counts.get)

                        #If someone in your dataset is identified, Open the door
                        if currentname != name:
                                currentname = name
                                logMsg(f"{timestamp()} Detected face: {currentname}")
                                if currentname != "Unknown":
                                    logMsg(f"{timestamp()} Opening door")
                                    html = urllib.request.urlopen("http://192.168.1.x:81/cgi-bin/sesam.cgi").read()
                                    currentname = "Unknown"

        # update the FPS counter
        fps.update()

# stop the timer and display FPS information
fps.stop()

# do a bit of cleanup
vs.stop()

Проверка прошла успешно, но хочется добавить видео лог, т.к. Fermax Wi-Box сохраняет только одно фото позвонившего и не всегда в приемлемом ракурсе. Будем использовать Motion https://github.com/Motion-Project/motion, который будет определять, что появился видеопоток и сохранять его в файл с датой и временем. Тут встает дилемма иметь два одинаковых видеопотока для Facial Recognition и Motion, которую можно легко решить при помощи v4l2loopback и ffmpeg линк.

Установим v4l2loopback.

sudo apt upgrade v4l2loopback-dkms

Создадим фаил /etc/modprobe.d/v4l2loopback.conf со следующим содержимым.

options v4l2loopback devices=2 exclusive_caps=1,1 video_nr=10,11 card_label="Motion Camera","OpenCV Camera"  

Загрузим модуль ядра и убедимся, что две новые виртуальные камеры созданы

sudo modprobe -r v4l2loopback
$ v4l2-ctl --list-devices

"Motion Camera" (platform:v4l2loopback-000):
        /dev/video10

"OpenCV Camera" (platform:v4l2loopback-001):
        /dev/video11

AV TO USB2.0 (usb-xhci-hcd.0-1):
        /dev/video0
        /dev/video1
        /dev/media3

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

sudo ffmpeg -f v4l2 -i /dev/video0 -f v4l2 /dev/video10 -f v4l2 /dev/video11 &

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

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

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

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

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

Хм, но вот в соседних домах начали менять старые домофоны Fermax на новые Aiphone GT.

Посмотрим, что нас ждет впереди.

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


  1. eagleivg
    21.05.2024 08:45

    А вот это давайте попробуем реализовать.

    А давайте не надо? Уже 100 раз показывалось, что камера элементарно обманывается обычной фотографией.


    1. sekuzmin Автор
      21.05.2024 08:45

      Я ждал такого комментария.
      Если в подъезд можно зайти просто за кем-то (piggyback), почему я буду беспокоится, что кто-то будет демонстрировать мое фото в камеру?
      Да и к тому же будет интересно это посмотреть потом на видео.


  1. VadimProfii
    21.05.2024 08:45

    Если не секрет, это где такое? И как биометрия путешествует- все остается в РФии по закону?


    1. sekuzmin Автор
      21.05.2024 08:45

      Абсолютно не секрет, биометрия остается на Raspberry Pi, запертая в кладовке. Не путешествует, это небезопасно в наше время.