2018-02-10 12:40:26 +01:00
|
|
|
# Compare incomming video with known faces
|
2018-01-05 16:37:00 +01:00
|
|
|
# Running in a local python instance to get around PATH issues
|
|
|
|
|
2018-02-20 22:18:29 +01:00
|
|
|
# Import time so we can start timing asap
|
|
|
|
import time
|
|
|
|
|
|
|
|
# Start timing
|
|
|
|
timings = [time.time()]
|
|
|
|
|
2018-01-05 16:37:00 +01:00
|
|
|
# Import required modules
|
2018-01-05 01:59:44 +01:00
|
|
|
import cv2
|
|
|
|
import sys
|
|
|
|
import os
|
2018-01-05 14:34:18 +01:00
|
|
|
import json
|
2018-02-13 16:31:30 +01:00
|
|
|
import math
|
2018-01-17 21:28:10 +01:00
|
|
|
import configparser
|
2018-01-05 01:59:44 +01:00
|
|
|
|
2018-02-01 16:01:17 +01:00
|
|
|
# Read config from disk
|
2018-01-17 21:28:10 +01:00
|
|
|
config = configparser.ConfigParser()
|
2018-02-01 16:01:17 +01:00
|
|
|
config.read(os.path.dirname(os.path.abspath(__file__)) + "/config.ini")
|
2018-01-05 02:41:56 +01:00
|
|
|
|
2018-01-05 01:59:44 +01:00
|
|
|
def stop(status):
|
2018-01-05 16:37:00 +01:00
|
|
|
"""Stop the execution and close video stream"""
|
2018-01-05 01:59:44 +01:00
|
|
|
video_capture.release()
|
|
|
|
sys.exit(status)
|
|
|
|
|
2018-01-05 16:37:00 +01:00
|
|
|
# Make sure we were given an username to tast against
|
2018-01-05 01:59:44 +01:00
|
|
|
try:
|
|
|
|
if not isinstance(sys.argv[1], str):
|
|
|
|
sys.exit(1)
|
|
|
|
except IndexError:
|
|
|
|
sys.exit(1)
|
|
|
|
|
2018-01-05 16:37:00 +01:00
|
|
|
# The username of the authenticating user
|
2018-01-05 01:59:44 +01:00
|
|
|
user = sys.argv[1]
|
2018-02-13 16:31:30 +01:00
|
|
|
# The model file contents
|
|
|
|
models = []
|
|
|
|
# Encoded face models
|
2018-01-05 01:59:44 +01:00
|
|
|
encodings = []
|
2018-01-05 16:37:00 +01:00
|
|
|
# Amount of frames already matched
|
2018-01-05 14:34:18 +01:00
|
|
|
tries = 0
|
2018-02-16 17:00:24 +01:00
|
|
|
# Amount of ingnored dark frames
|
|
|
|
dark_tries = 0
|
2018-01-05 01:59:44 +01:00
|
|
|
|
2018-01-05 16:37:00 +01:00
|
|
|
# Try to load the face model from the models folder
|
2018-01-05 01:59:44 +01:00
|
|
|
try:
|
2018-02-13 16:31:30 +01:00
|
|
|
models = json.load(open(os.path.dirname(os.path.abspath(__file__)) + "/models/" + user + ".dat"))
|
2018-01-05 01:59:44 +01:00
|
|
|
except FileNotFoundError:
|
2018-01-17 21:28:10 +01:00
|
|
|
sys.exit(10)
|
2018-01-05 01:59:44 +01:00
|
|
|
|
2018-02-13 16:31:30 +01:00
|
|
|
# Check if the file contains a model
|
|
|
|
if len(models) < 1:
|
|
|
|
sys.exit(10)
|
|
|
|
|
|
|
|
# Put all models together into 1 array
|
|
|
|
for model in models:
|
|
|
|
encodings += model["data"]
|
2018-01-05 14:34:18 +01:00
|
|
|
|
2018-02-20 22:18:29 +01:00
|
|
|
# Add the time needed to start the script
|
2018-02-13 22:03:03 +01:00
|
|
|
timings.append(time.time())
|
|
|
|
|
2018-01-05 16:37:00 +01:00
|
|
|
# Start video capture on the IR camera
|
2018-01-17 21:28:10 +01:00
|
|
|
video_capture = cv2.VideoCapture(int(config.get("video", "device_id")))
|
2018-02-20 22:18:29 +01:00
|
|
|
|
|
|
|
# Capture a single frame so the camera becomes active
|
|
|
|
# This will let the camera adjust its light levels while we're importing for faster scanning
|
|
|
|
video_capture.read()
|
|
|
|
|
|
|
|
# Note the time it took to open the camera
|
|
|
|
timings.append(time.time())
|
|
|
|
|
|
|
|
# Import face recognition, takes some time
|
|
|
|
import face_recognition
|
2018-02-13 16:31:30 +01:00
|
|
|
timings.append(time.time())
|
2018-01-05 01:59:44 +01:00
|
|
|
|
2018-02-13 22:49:29 +01:00
|
|
|
# Fetch the max frame height
|
|
|
|
max_height = int(config.get("video", "max_height"))
|
|
|
|
|
2018-02-13 16:31:30 +01:00
|
|
|
# Start the read loop
|
|
|
|
frames = 0
|
2018-01-05 01:59:44 +01:00
|
|
|
while True:
|
2018-02-13 16:31:30 +01:00
|
|
|
frames += 1
|
|
|
|
|
2018-01-05 01:59:44 +01:00
|
|
|
# Grab a single frame of video
|
2018-02-13 16:31:30 +01:00
|
|
|
# Don't remove ret, it doesn't work without it
|
2018-01-05 01:59:44 +01:00
|
|
|
ret, frame = video_capture.read()
|
|
|
|
|
2018-02-16 17:00:24 +01:00
|
|
|
# Create a histogram of the image with 8 values
|
|
|
|
hist = cv2.calcHist([frame], [0], None, [8], [0, 256])
|
|
|
|
# All values combined for percentage calculation
|
|
|
|
hist_total = int(sum(hist)[0])
|
|
|
|
|
|
|
|
# Scrip the frame if it exceeds the threshold
|
|
|
|
if float(hist[0]) / hist_total * 100 > float(config.get("video", "dark_threshold")):
|
|
|
|
dark_tries += 1
|
|
|
|
continue
|
|
|
|
|
2018-02-13 23:22:13 +01:00
|
|
|
# Get the height and with of the image
|
2018-02-13 22:49:29 +01:00
|
|
|
height, width = frame.shape[:2]
|
|
|
|
|
2018-02-13 23:22:13 +01:00
|
|
|
# If the hight is too high
|
2018-02-13 22:49:29 +01:00
|
|
|
if max_height < height:
|
2018-02-13 23:22:13 +01:00
|
|
|
# Calculate the amount the image has to shrink
|
2018-02-13 22:49:29 +01:00
|
|
|
scaling_factor = max_height / float(height)
|
2018-02-13 23:22:13 +01:00
|
|
|
# Apply that factor to the frame
|
2018-02-13 22:49:29 +01:00
|
|
|
frame = cv2.resize(frame, None, fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_AREA)
|
|
|
|
|
2018-02-13 23:22:13 +01:00
|
|
|
# Save the new size for diagnostics
|
2018-02-13 22:49:29 +01:00
|
|
|
scale_height, scale_width = frame.shape[:2]
|
|
|
|
|
|
|
|
# Convert from BGR to RGB
|
|
|
|
frame = frame[:, :, ::-1]
|
|
|
|
|
2018-01-05 16:37:00 +01:00
|
|
|
# Get all faces from that frame as encodings
|
2018-01-05 01:59:44 +01:00
|
|
|
face_encodings = face_recognition.face_encodings(frame)
|
|
|
|
|
2018-01-05 16:37:00 +01:00
|
|
|
# Loop through each face
|
2018-01-05 01:59:44 +01:00
|
|
|
for face_encoding in face_encodings:
|
2018-01-05 16:37:00 +01:00
|
|
|
# Match this found face against a known face
|
2018-01-05 01:59:44 +01:00
|
|
|
matches = face_recognition.face_distance(encodings, face_encoding)
|
|
|
|
|
2018-01-05 16:37:00 +01:00
|
|
|
# Check if any match is certain enough to be the user we're looking for
|
2018-02-13 16:31:30 +01:00
|
|
|
match_index = 0
|
2018-01-05 01:59:44 +01:00
|
|
|
for match in matches:
|
2018-02-13 16:31:30 +01:00
|
|
|
match_index += 1
|
|
|
|
|
|
|
|
# Try to find a match that's confident enough
|
|
|
|
if match * 10 < float(config.get("video", "certainty")) and match > 0:
|
|
|
|
timings.append(time.time())
|
|
|
|
|
|
|
|
# If set to true in the config, print debug text
|
|
|
|
if config.get("debug", "end_report") == "true":
|
2018-02-13 22:03:03 +01:00
|
|
|
def print_timing(label, offset):
|
|
|
|
"""Helper function to print a timing from the list"""
|
|
|
|
print(" " + label + ": " + str(round((timings[1 + offset] - timings[offset]) * 1000)) + "ms")
|
|
|
|
|
2018-02-13 16:31:30 +01:00
|
|
|
print("Time spend")
|
2018-02-13 22:03:03 +01:00
|
|
|
print_timing("Starting up", 0)
|
2018-02-20 22:18:29 +01:00
|
|
|
print_timing("Opening the camera", 1)
|
|
|
|
print_timing("Importing face_recognition", 2)
|
2018-02-13 22:03:03 +01:00
|
|
|
print_timing("Searching for known face", 3)
|
2018-02-13 16:31:30 +01:00
|
|
|
|
2018-02-13 22:49:29 +01:00
|
|
|
print("\nResolution")
|
|
|
|
print(" Native: " + str(height) + "x" + str(width))
|
|
|
|
print(" Used: " + str(scale_height) + "x" + str(scale_width))
|
|
|
|
|
2018-02-20 22:18:29 +01:00
|
|
|
# Show the total number of frames and calculate the FPS by deviding it by the total scan time
|
|
|
|
print("\nFrames searched: " + str(frames) + " (" + str(round(float(frames) / (timings[4] - timings[3]), 2)) + " fps)")
|
2018-02-16 17:00:24 +01:00
|
|
|
print("Dark frames ignored: " + str(dark_tries))
|
2018-02-13 22:03:03 +01:00
|
|
|
print("Certainty of winning frame: " + str(round(match * 10, 3)))
|
2018-02-13 16:31:30 +01:00
|
|
|
|
2018-02-16 16:28:10 +01:00
|
|
|
# Catch older 3-encoding models
|
|
|
|
if not match_index in models:
|
|
|
|
match_index = 0
|
2018-02-13 16:31:30 +01:00
|
|
|
|
2018-02-16 16:28:10 +01:00
|
|
|
print("Winning model: " + str(match_index) + " (\"" + models[match_index]["label"] + "\")")
|
2018-02-13 16:31:30 +01:00
|
|
|
|
|
|
|
# End peacegully
|
2018-01-05 01:59:44 +01:00
|
|
|
stop(0)
|
|
|
|
|
2018-01-05 16:37:00 +01:00
|
|
|
# Stop if we've exceded the maximum retry count
|
2018-02-13 22:49:29 +01:00
|
|
|
if time.time() - timings[3] > int(config.get("video", "timout")):
|
2018-01-05 02:41:56 +01:00
|
|
|
stop(11)
|
2018-01-05 01:59:44 +01:00
|
|
|
|
|
|
|
tries += 1
|