Gesichtserkennung Raspberry GPIO Schaltung

Mich haben zuletzt vermehrt Anfragen erreicht, die GPIOs mit der Gesichtserkennung zu kombinieren. Zum Beispiel als Schaltung für die Garage oder das eine LED für eine bestimmte Zeit aktiviert ist. Zudem wäre eine Benachrichtung aufs Smartphone interessant. Diesen Anfragen möchte ich mit diesem Beitrag gerecht werden. Die Anforderung an mich selber waren, dass für jedes Gesicht, welches die Software im Frame erkennt, das Script eine Nachricht an das Smartphone schicken soll. Für jedes bekannte Gesicht soll zusätzlich die LED für 5 Sekunden laufen. Für die Smartphone Benachrichtigung habe ich Pushbullet verwendet. Pushbullet stellt eine App bereit und es stehen mehrere Python Module zur Verfügung. Ich habe die eigene von Pushbullet verwendet.

sudo pip3 install pushbullet.py

Für die Registrierung benötigt man einen Google oder Facebook Account.

Auf der Seite könnt ihr den API Key unter Access Tokens einsehen. Diesen Schlüssel übertragt ihr bei jeder Push Nachricht mit. Ich empfehle euch, die End-zu-End Verschlüsselung zu aktivieren. Ihr müsst ein einmaliges Passwort eintragen. Jedes Gerät das ihr bei Pushbullet registriert habt, benötigt diesen Schlüssel, um die Nachrichten zu entschlüsseln.

 

Für die Schaltung habe ich ein Steckbrett mit LED und Widerstand benutzt. Auf dem Pi ist der GPIO Pin 17 angeschlossen. Es ist euch selber überlassen, welchen Pin ihr nehmt, ihr müsst diesen nur vernünftig schalten können.

Damit hätten wir alles Organisatorische geregelt. Kommen wir nun also zum Code, der an die anderen Gesichtserkennungs-Beiträgen angelehnt ist. Ich habe hier zusätzlich Threads mit eingebaut, damit die Abarbeitung der Notifications oder die Schaltung der LED neben dem Main-Thread laufen können. Die Threads rufen jeweils Funktionen auf, daher besteht für die Notification, als auch für die LED Schaltung eine eigenständige Funktion, denen ich Argumente übergebe. Damit ein Thread nicht doppelt aufgerufen werden kann, habe ich mit if tgpio not in threading.enumerate(): eine Verriegelung eingebaut. threading.enumerate() enthält jede zurzeit aktive Thread-ID.

Funktion NotifyPushbullet:

Ein Foto wird zwar außerhalb der Funktion gemacht, aber immer dann, wenn das Script ein Gesicht im Frame entdeckt hat. Das Foto ist lokal gespeichert, bevor die Funktion NotifyPushbullet es verschickt. Ich lege diese Funktion danach noch 30 Sekunden „schlafen“, um eine weitere unnötige Notifications zu vermeiden.

Funktion FaceGPIO:

Die LED wird geschaltet, wenn ein bekanntes Gesicht im Frame ist. Sobald eines erkannt wurde, leuchtet die LED für 12 Sekunden, ehe sie sich selber wieder ausschaltet. Falls es bei den GPIOs zu Fehlern kommt, z.B. eine Doppelbelegung des Pins, löst eine Exception aus und gibt den Fehler im Terminal zurück.

Weiter unten findet ihr den Code. Ich habe einige Einträge kommentiert, die helfen sollen den Code einfacher zu verstehen.

# This program will print out the names of anyone it recognizes to the console.

# To run this, you need a Raspberry Pi 2 (or greater) with face_recognition and
# the picamera[array] module installed.
# You can follow this installation instructions to get your RPi set up:
# https://gist.github.com/ageitgey/1ac8dbe8572f3f533df6269dab35df65

try:
    import face_recognition
    import picamera
    import numpy as np
    import os
    import datetime
    from pushbullet import Pushbullet
    import gpiozero
    from time import sleep
    import threading

except:
    print("failed to load module")
    exit()


# Initialize some variables
tpush = None
tgpio = None
face_locations = []
face_encodings = []
image = []
known_face_encoding = []
known_faces = []

# Set some variables
pb = Pushbullet('apikey')
framerate = 15

def NotifyPushbullet(pb,file):
    #push notification
    push = pb.push_note("Face detected","Someone was detected")
    # push image
    with open(file, "rb") as pic:
    file_data = pb.upload_file(pic, "picture.jpg")
    push = pb.push_file(**file_data)
    # set NotifyPushbullet to sleep
    print("Push Notification sent")
    sleep(30)


# Function for GPIO
def FaceGPIO(timetosleep):
    try:
        #initialize LED
        led = gpiozero.LED(17)
        # switch LED on
        led.on()
        #set to sleep
        sleep(timetosleep)
        # switch LED off
        led.off()
    # if any error occurs call exception
    except gpiozero.GPIOZeroError as err:
        print("Error occured: {0}".format(err))

# Get a reference to the Raspberry Pi camera.
# If this fails, make sure you have a camera connected to the RPi and that you
# enabled your camera in raspi-config and rebooted first.
try:
    camera = picamera.PiCamera()
    camera.resolution = (320, 240)
    camera.framerate = framerate
    output = np.empty((240, 320, 3), dtype=np.uint8)
except:
    print("something went wrong while initialize camera")
    exit()

# Load pictures and learn how to recognize it.
print("Loading known face image(s)")

#is loading all images in faces/ and create a stamp
try:
    for faces,i in zip(os.listdir("faces"),range(len(os.listdir("faces")))):
        known_faces.append("faces/"+faces)
        image.append(face_recognition.load_image_file("faces/" + faces))
        known_face_encoding.append(face_recognition.face_encodings(image[i])[0])
except:
    print("could not find known pictures")
    exit()


while True:
    print("Capturing image.")
    # Grab a single frame of video from the RPi camera as a numpy array
    camera.capture(output, format="rgb")

    # Find all the faces and face encodings in the current frame of video
    face_locations = face_recognition.face_locations(output)
    print("Found {} faces in image.".format(len(face_locations)))
    face_encodings = face_recognition.face_encodings(output, face_locations)

    #print all active threads
    print(threading.enumerate())

    # Loop over each face found in the frame to see if it's someone we know.
    for face_encoding in face_encodings:

        # make a picture
        camera.capture('/home/pi/image.jpg', use_video_port=True)
        # create a thread to push Notifications
        # check if such a thread already exists
        if tpush not in threading.enumerate():
            #define thread
            tpush = threading.Thread(target=NotifyPushbullet,args=(pb,'/home/pi/image.jpg',))
            #start thread
            tpush.start()
        else:
            # if a thread was started already and still is running
            print("Thread tpush already started: {0}".format(str(tpush)))

        for face, i in zip(os.listdir("faces"), range(len(known_faces))):

            if face_recognition.compare_faces([known_face_encoding[i]], face_encoding,0.6)[0]:
                #print found face all upper case
                print("<found: ".upper() + known_faces[i].upper() + ">")

                #create a thread to switch the LED on
                # check if such a thread already exists
                if tgpio not in threading.enumerate():
                    #define thread; call function FaceGPIO with argument
                    tgpio = threading.Thread(target=FaceGPIO,args=(5,))
                    #start thread
                    tgpio.start()
                else:
                    # if a thread was started already and still is running
                    print("Thread tgpio already started: {0}".format(str(tgpio)))

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert