From 5b6ca8525ce50b4e4a461b2f2cd1d021a3f4252e Mon Sep 17 00:00:00 2001 From: dmig Date: Sun, 18 Nov 2018 13:45:13 +0700 Subject: [PATCH 1/6] use ConfigParser.get*() functions; move config reading out of maincycle; drop unused import --- src/compare.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/compare.py b/src/compare.py index 62824d6..5b24c22 100644 --- a/src/compare.py +++ b/src/compare.py @@ -12,7 +12,6 @@ import cv2 import sys import os import json -import math import configparser # Read config from disk @@ -61,16 +60,18 @@ timings.append(time.time()) video_capture = cv2.VideoCapture(config.get("video", "device_path")) # Force MJPEG decoding if true -if config.get("video", "force_mjpeg") == "true": +if config.getboolean("video", "force_mjpeg"): # Set a magic number, will enable MJPEG but is badly documentated video_capture.set(cv2.CAP_PROP_FOURCC, 1196444237) # Set the frame width and height if requested -if int(config.get("video", "frame_width")) != -1: - video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, int(config.get("video", "frame_width"))) +fw = config.getint("video", "frame_width") +fh = config.getint("video", "frame_height") +if fw != -1: + video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, fw) -if int(config.get("video", "frame_height")) != -1: - video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, int(config.get("video", "frame_height"))) +if fh != -1: + video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, fh) # 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 @@ -88,12 +89,15 @@ max_height = int(config.get("video", "max_height")) # Start the read loop frames = 0 +timeout = config.getint("video", "timout") +dark_threshold = config.getfloat("video", "dark_threshold") +end_report = config.getboolean("debug", "end_report") while True: # Increment the frame count every loop frames += 1 # Stop if we've exceded the time limit - if time.time() - timings[3] > int(config.get("video", "timout")): + if time.time() - timings[3] > timeout: stop(11) # Grab a single frame of video @@ -111,7 +115,7 @@ while True: continue # Scrip the frame if it exceeds the threshold - if float(hist[0]) / hist_total * 100 > float(config.get("video", "dark_threshold")): + if float(hist[0]) / hist_total * 100 > dark_threshold: dark_tries += 1 continue @@ -146,12 +150,12 @@ while True: timings.append(time.time()) # If set to true in the config, print debug text - if config.get("debug", "end_report") == "true": + if end_report: 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") - print("Time spend") + print("Time spent") print_timing("Starting up", 0) print_timing("Opening the camera", 1) print_timing("Importing face_recognition", 2) From 56cf32388a8b2c98ea2517ff7c17c90ee49853ed Mon Sep 17 00:00:00 2001 From: dmig Date: Sun, 18 Nov 2018 13:46:20 +0700 Subject: [PATCH 2/6] use ConfigParser.get*() function --- src/pam.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pam.py b/src/pam.py index 42ee919..6de8f19 100644 --- a/src/pam.py +++ b/src/pam.py @@ -16,11 +16,11 @@ def doAuth(pamh): """Starts authentication in a seperate process""" # Abort is Howdy is disabled - if config.get("core", "disabled") == "true": + if config.getboolean("core", "disabled"): sys.exit(0) # Abort if we're in a remote SSH env - if config.get("core", "ignore_ssh") == "true": + if config.getboolean("core", "ignore_ssh"): if "SSH_CONNECTION" in os.environ or "SSH_CLIENT" in os.environ or "SSHD_OPTS" in os.environ: sys.exit(0) @@ -29,7 +29,7 @@ def doAuth(pamh): # Status 10 means we couldn't find any face models if status == 10: - if config.get("core", "suppress_unknown") != "true": + if not config.getboolean("core", "suppress_unknown"): pamh.conversation(pamh.Message(pamh.PAM_ERROR_MSG, "No face model known")) return pamh.PAM_USER_UNKNOWN # Status 11 means we exceded the maximum retry count @@ -39,11 +39,11 @@ def doAuth(pamh): # Status 0 is a successful exit if status == 0: # Show the success message if it isn't suppressed - if config.get("core", "no_confirmation") != "true": + if not config.getboolean("core", "no_confirmation"): pamh.conversation(pamh.Message(pamh.PAM_TEXT_INFO, "Identified face as " + pamh.get_user())) # Try to dismiss the lock screen if enabled - if config.get("core", "dismiss_lockscreen") == "true": + if config.get("core", "dismiss_lockscreen"): # Run it as root with a timeout of 1s, and never ask for a password through the UI subprocess.Popen(["sudo", "timeout", "1", "loginctl", "unlock-sessions", "--no-ask-password"]) From fa51ff7c10b50e662ac67df384b5397b0f36001d Mon Sep 17 00:00:00 2001 From: dmig Date: Sun, 18 Nov 2018 13:48:02 +0700 Subject: [PATCH 3/6] use ConfigParser.get*() functions; drop unused import --- src/cli/add.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/cli/add.py b/src/cli/add.py index 8df9c65..243d478 100644 --- a/src/cli/add.py +++ b/src/cli/add.py @@ -1,7 +1,6 @@ # Save the face of the user in encoded form # Import required modules -import subprocess import time import os import sys @@ -82,15 +81,18 @@ insert_model = { video_capture = cv2.VideoCapture(config.get("video", "device_path")) # Force MJPEG decoding if true -if config.get("video", "force_mjpeg") == "true": +if config.getboolean("video", "force_mjpeg"): + # Set a magic number, will enable MJPEG but is badly documentated video_capture.set(cv2.CAP_PROP_FOURCC, 1196444237) # Set the frame width and height if requested -if int(config.get("video", "frame_width")) != -1: - video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, int(config.get("video", "frame_width"))) +fw = config.getint("video", "frame_width") +fh = config.getint("video", "frame_height") +if fw != -1: + video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, fw) -if int(config.get("video", "frame_height")) != -1: - video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, int(config.get("video", "frame_height"))) +if fh != -1: + video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, fh) # Request a frame to wake the camera up video_capture.read() From 964e96377c09d5b1a892c9eeba77c037977c0987 Mon Sep 17 00:00:00 2001 From: dmig Date: Sun, 18 Nov 2018 13:49:16 +0700 Subject: [PATCH 4/6] use ConfigParser.get*() functions; move function definition out of main cycle; drop unused import; show recognition time --- src/cli/test.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/cli/test.py b/src/cli/test.py index 3a55053..e6f495c 100644 --- a/src/cli/test.py +++ b/src/cli/test.py @@ -21,15 +21,18 @@ config.read(path + "/../config.ini") video_capture = cv2.VideoCapture(config.get("video", "device_path")) # Force MJPEG decoding if true -if config.get("video", "force_mjpeg") == "true": +if config.getboolean("video", "force_mjpeg"): + # Set a magic number, will enable MJPEG but is badly documented video_capture.set(cv2.CAP_PROP_FOURCC, 1196444237) # Set the frame width and height if requested -if int(config.get("video", "frame_width")) != -1: - video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, int(config.get("video", "frame_width"))) +fw = config.getint("video", "frame_width") +fh = config.getint("video", "frame_height") +if fw != -1: + video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, fw) -if int(config.get("video", "frame_height")) != -1: - video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, int(config.get("video", "frame_height"))) +if fh != -1: + video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, fh) # Let the user know what's up print(""" @@ -47,6 +50,10 @@ def mouse(event, x, y, flags, param): if event == cv2.EVENT_LBUTTONDOWN: slow_mode = not slow_mode +def print_text(line_number, text): + """Print the status text by line number""" + cv2.putText(overlay, text, (10, height - 10 - (10 * line_number)), cv2.FONT_HERSHEY_SIMPLEX, .3, (0, 255, 0), 0, cv2.LINE_AA) + # Open the window and attach a a mouse listener cv2.namedWindow("Howdy Test") cv2.setMouseCallback("Howdy Test", mouse) @@ -61,11 +68,13 @@ sec_frames = 0 fps = 0 # The current second we're counting sec = int(time.time()) +# recognition time +rec_tm = 0 # Wrap everything in an keyboard interupt handler try: while True: - # Inclement the frames + # Increment the frames total_frames += 1 sec_frames += 1 @@ -109,14 +118,11 @@ try: # Draw a stripe indicating the dark threshold cv2.rectangle(overlay, (8, 35), (20, 36), (255, 0, 0), thickness=cv2.FILLED) - def print_text(line_number, text): - """Print the status text by line number""" - cv2.putText(overlay, text, (10, height - 10 - (10 * line_number)), cv2.FONT_HERSHEY_SIMPLEX, .3, (0, 255, 0), 0, cv2.LINE_AA) - # Print the statis in the bottom left - print_text(0, "RESOLUTION: " + str(height) + "x" + str(width)) - print_text(1, "FPS: " + str(fps)) - print_text(2, "FRAMES: " + str(total_frames)) + print_text(0, "RESOLUTION: %dx%d" % (height, width)) + print_text(1, "FPS: %d" % (fps, )) + print_text(2, "FRAMES: %d" % (total_frames, )) + print_text(3, "RECOGNITION: %dms" % (round(rec_tm * 1000), )) # Show that slow mode is on, if it's on if slow_mode: @@ -130,8 +136,10 @@ try: # SHow that this is an active frame cv2.putText(overlay, "SCAN FRAME", (width - 68, 16), cv2.FONT_HERSHEY_SIMPLEX, .3, (0, 255, 0), 0, cv2.LINE_AA) + rec_tm = time.time() # Get the locations of all faces and their locations face_locations = face_recognition.face_locations(frame) + rec_tm = time.time() - rec_tm # Loop though all faces and paint a circle around them for loc in face_locations: From b8aa070600d7690f0ad4b7023f4bb1ecfb9a3a3d Mon Sep 17 00:00:00 2001 From: dmig Date: Sun, 18 Nov 2018 13:55:58 +0700 Subject: [PATCH 5/6] remove unused imports --- src/cli.py | 1 - src/cli/test.py | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/cli.py b/src/cli.py index a937594..7f8a79c 100755 --- a/src/cli.py +++ b/src/cli.py @@ -4,7 +4,6 @@ # Import required modules import sys import os -import subprocess import getpass import argparse import builtins diff --git a/src/cli/test.py b/src/cli/test.py index e6f495c..cceb1a4 100644 --- a/src/cli/test.py +++ b/src/cli/test.py @@ -1,14 +1,11 @@ # Show a windows with the video stream and testing information # Import required modules -import face_recognition -import cv2 import configparser import os -import sys -import json -import numpy import time +import cv2 +import face_recognition # Get the absolute path to the current file path = os.path.dirname(os.path.abspath(__file__)) From 59e622c17db527c68d33c19f73f2c294c5be03c7 Mon Sep 17 00:00:00 2001 From: dmig Date: Sun, 18 Nov 2018 13:56:52 +0700 Subject: [PATCH 6/6] minor code readability changes --- src/cli.py | 2 +- src/cli/add.py | 12 +++++------- src/compare.py | 23 +++++++++++------------ 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/cli.py b/src/cli.py index 7f8a79c..2c5d877 100755 --- a/src/cli.py +++ b/src/cli.py @@ -15,7 +15,7 @@ except: user = os.environ.get("SUDO_USER") # If that fails, try to get the direct user -if user == "root" or user == None: +if user == "root" or user is None: env_user = getpass.getuser().strip() # If even that fails, error out diff --git a/src/cli/add.py b/src/cli/add.py index 243d478..4fe11d8 100644 --- a/src/cli/add.py +++ b/src/cli/add.py @@ -5,9 +5,9 @@ import time import os import sys import json -import cv2 import configparser import builtins +import cv2 # Try to import face_recognition and give a nice error if we can't # Add should be the first point where import issues show up @@ -55,12 +55,12 @@ print("Adding face model for the user " + user) label = "Initial model" # If models already exist, set that default label -if len(encodings) > 0: +if encodings: label = "Model #" + str(len(encodings) + 1) # Keep de default name if we can't ask questions if builtins.howdy_args.y: - print("Using default label \"" + label + "\" because of -y flag") + print('Using default label "%s" because of -y flag' % (label, )) else: # Ask the user for a custom label label_in = input("Enter a label for this new model [" + label + "]: ") @@ -119,11 +119,9 @@ while frames < 60: enc = face_recognition.face_encodings(frame) # If we've found at least one, we can continue - if len(enc) > 0: + if enc: break - -# If 0 faces are detected we can't continue -if len(enc) == 0: +else: print("No face detected, aborting") sys.exit(1) diff --git a/src/compare.py b/src/compare.py index 5b24c22..dca8a88 100644 --- a/src/compare.py +++ b/src/compare.py @@ -42,17 +42,16 @@ dark_tries = 0 # Try to load the face model from the models folder try: models = json.load(open(os.path.dirname(os.path.abspath(__file__)) + "/models/" + user + ".dat")) + + # Put all models together into 1 array + encodings = [model["data"] for model in models] except FileNotFoundError: sys.exit(10) # Check if the file contains a model -if len(models) < 1: +if not encodings: sys.exit(10) -# Put all models together into 1 array -for model in models: - encodings += model["data"] - # Add the time needed to start the script timings.append(time.time()) @@ -153,7 +152,7 @@ while True: if end_report: 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") + print(" %s: %dms" % (label, round((timings[1 + offset] - timings[offset]) * 1000))) print("Time spent") print_timing("Starting up", 0) @@ -162,19 +161,19 @@ while True: print_timing("Searching for known face", 3) print("\nResolution") - print(" Native: " + str(height) + "x" + str(width)) - print(" Used: " + str(scale_height) + "x" + str(scale_width)) + print(" Native: %dx%d" % (height, width)) + print(" Used: %dx%d" % (scale_height, scale_width)) # 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)") - print("Dark frames ignored: " + str(dark_tries)) - print("Certainty of winning frame: " + str(round(match * 10, 3))) + print("\nFrames searched: %d (%.2f fps)" % (frames, frames / (timings[4] - timings[3]))) + print("Dark frames ignored: %d " % (dark_tries, )) + print("Certainty of winning frame: %.3f" % (match * 10, )) # Catch older 3-encoding models if not match_index in models: match_index = 0 - print("Winning model: " + str(match_index) + " (\"" + models[match_index]["label"] + "\")") + print("Winning model: %d (\"%s\")" % (match_index, models[match_index]["label"])) # End peacefully stop(0)