Merge pull request #98 from dmig/master

code quality update
This commit is contained in:
boltgolt 2018-11-19 10:55:11 +01:00 committed by GitHub
commit 23088907ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 60 deletions

View file

@ -4,7 +4,6 @@
# Import required modules # Import required modules
import sys import sys
import os import os
import subprocess
import getpass import getpass
import argparse import argparse
import builtins import builtins
@ -16,7 +15,7 @@ except:
user = os.environ.get("SUDO_USER") user = os.environ.get("SUDO_USER")
# If that fails, try to get the direct 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() env_user = getpass.getuser().strip()
# If even that fails, error out # If even that fails, error out

View file

@ -1,14 +1,13 @@
# Save the face of the user in encoded form # Save the face of the user in encoded form
# Import required modules # Import required modules
import subprocess
import time import time
import os import os
import sys import sys
import json import json
import cv2
import configparser import configparser
import builtins import builtins
import cv2
# Try to import face_recognition and give a nice error if we can't # 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 # Add should be the first point where import issues show up
@ -56,12 +55,12 @@ print("Adding face model for the user " + user)
label = "Initial model" label = "Initial model"
# If models already exist, set that default label # If models already exist, set that default label
if len(encodings) > 0: if encodings:
label = "Model #" + str(len(encodings) + 1) label = "Model #" + str(len(encodings) + 1)
# Keep de default name if we can't ask questions # Keep de default name if we can't ask questions
if builtins.howdy_args.y: 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: else:
# Ask the user for a custom label # Ask the user for a custom label
label_in = input("Enter a label for this new model [" + label + "]: ") label_in = input("Enter a label for this new model [" + label + "]: ")
@ -82,15 +81,18 @@ insert_model = {
video_capture = cv2.VideoCapture(config.get("video", "device_path")) video_capture = cv2.VideoCapture(config.get("video", "device_path"))
# Force MJPEG decoding if true # 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) video_capture.set(cv2.CAP_PROP_FOURCC, 1196444237)
# Set the frame width and height if requested # Set the frame width and height if requested
if int(config.get("video", "frame_width")) != -1: fw = config.getint("video", "frame_width")
video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, int(config.get("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: if fh != -1:
video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, int(config.get("video", "frame_height"))) video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, fh)
# Request a frame to wake the camera up # Request a frame to wake the camera up
video_capture.read() video_capture.read()
@ -117,11 +119,9 @@ while frames < 60:
enc = face_recognition.face_encodings(frame) enc = face_recognition.face_encodings(frame)
# If we've found at least one, we can continue # If we've found at least one, we can continue
if len(enc) > 0: if enc:
break break
else:
# If 0 faces are detected we can't continue
if len(enc) == 0:
print("No face detected, aborting") print("No face detected, aborting")
sys.exit(1) sys.exit(1)

View file

@ -1,14 +1,11 @@
# Show a windows with the video stream and testing information # Show a windows with the video stream and testing information
# Import required modules # Import required modules
import face_recognition
import cv2
import configparser import configparser
import os import os
import sys
import json
import numpy
import time import time
import cv2
import face_recognition
# Get the absolute path to the current file # Get the absolute path to the current file
path = os.path.dirname(os.path.abspath(__file__)) path = os.path.dirname(os.path.abspath(__file__))
@ -21,15 +18,18 @@ config.read(path + "/../config.ini")
video_capture = cv2.VideoCapture(config.get("video", "device_path")) video_capture = cv2.VideoCapture(config.get("video", "device_path"))
# Force MJPEG decoding if true # 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) video_capture.set(cv2.CAP_PROP_FOURCC, 1196444237)
# Set the frame width and height if requested # Set the frame width and height if requested
if int(config.get("video", "frame_width")) != -1: fw = config.getint("video", "frame_width")
video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, int(config.get("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: if fh != -1:
video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, int(config.get("video", "frame_height"))) video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, fh)
# Let the user know what's up # Let the user know what's up
print(""" print("""
@ -47,6 +47,10 @@ def mouse(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN: if event == cv2.EVENT_LBUTTONDOWN:
slow_mode = not slow_mode 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 # Open the window and attach a a mouse listener
cv2.namedWindow("Howdy Test") cv2.namedWindow("Howdy Test")
cv2.setMouseCallback("Howdy Test", mouse) cv2.setMouseCallback("Howdy Test", mouse)
@ -61,11 +65,13 @@ sec_frames = 0
fps = 0 fps = 0
# The current second we're counting # The current second we're counting
sec = int(time.time()) sec = int(time.time())
# recognition time
rec_tm = 0
# Wrap everything in an keyboard interupt handler # Wrap everything in an keyboard interupt handler
try: try:
while True: while True:
# Inclement the frames # Increment the frames
total_frames += 1 total_frames += 1
sec_frames += 1 sec_frames += 1
@ -109,14 +115,11 @@ try:
# Draw a stripe indicating the dark threshold # Draw a stripe indicating the dark threshold
cv2.rectangle(overlay, (8, 35), (20, 36), (255, 0, 0), thickness=cv2.FILLED) 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 the statis in the bottom left
print_text(0, "RESOLUTION: " + str(height) + "x" + str(width)) print_text(0, "RESOLUTION: %dx%d" % (height, width))
print_text(1, "FPS: " + str(fps)) print_text(1, "FPS: %d" % (fps, ))
print_text(2, "FRAMES: " + str(total_frames)) 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 # Show that slow mode is on, if it's on
if slow_mode: if slow_mode:
@ -130,8 +133,10 @@ try:
# SHow that this is an active frame # 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) 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 # Get the locations of all faces and their locations
face_locations = face_recognition.face_locations(frame) face_locations = face_recognition.face_locations(frame)
rec_tm = time.time() - rec_tm
# Loop though all faces and paint a circle around them # Loop though all faces and paint a circle around them
for loc in face_locations: for loc in face_locations:

View file

@ -12,7 +12,6 @@ import cv2
import sys import sys
import os import os
import json import json
import math
import configparser import configparser
# Read config from disk # Read config from disk
@ -43,17 +42,16 @@ dark_tries = 0
# Try to load the face model from the models folder # Try to load the face model from the models folder
try: try:
models = json.load(open(os.path.dirname(os.path.abspath(__file__)) + "/models/" + user + ".dat")) 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: except FileNotFoundError:
sys.exit(10) sys.exit(10)
# Check if the file contains a model # Check if the file contains a model
if len(models) < 1: if not encodings:
sys.exit(10) 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 # Add the time needed to start the script
timings.append(time.time()) timings.append(time.time())
@ -61,16 +59,18 @@ timings.append(time.time())
video_capture = cv2.VideoCapture(config.get("video", "device_path")) video_capture = cv2.VideoCapture(config.get("video", "device_path"))
# Force MJPEG decoding if true # 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 # Set a magic number, will enable MJPEG but is badly documentated
video_capture.set(cv2.CAP_PROP_FOURCC, 1196444237) video_capture.set(cv2.CAP_PROP_FOURCC, 1196444237)
# Set the frame width and height if requested # Set the frame width and height if requested
if int(config.get("video", "frame_width")) != -1: fw = config.getint("video", "frame_width")
video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, int(config.get("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: if fh != -1:
video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, int(config.get("video", "frame_height"))) video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, fh)
# Capture a single frame so the camera becomes active # 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 # This will let the camera adjust its light levels while we're importing for faster scanning
@ -88,12 +88,15 @@ max_height = int(config.get("video", "max_height"))
# Start the read loop # Start the read loop
frames = 0 frames = 0
timeout = config.getint("video", "timout")
dark_threshold = config.getfloat("video", "dark_threshold")
end_report = config.getboolean("debug", "end_report")
while True: while True:
# Increment the frame count every loop # Increment the frame count every loop
frames += 1 frames += 1
# Stop if we've exceded the time limit # 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) stop(11)
# Grab a single frame of video # Grab a single frame of video
@ -111,7 +114,7 @@ while True:
continue continue
# Scrip the frame if it exceeds the threshold # 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 dark_tries += 1
continue continue
@ -146,31 +149,31 @@ while True:
timings.append(time.time()) timings.append(time.time())
# If set to true in the config, print debug text # 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): def print_timing(label, offset):
"""Helper function to print a timing from the list""" """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 spend") print("Time spent")
print_timing("Starting up", 0) print_timing("Starting up", 0)
print_timing("Opening the camera", 1) print_timing("Opening the camera", 1)
print_timing("Importing face_recognition", 2) print_timing("Importing face_recognition", 2)
print_timing("Searching for known face", 3) print_timing("Searching for known face", 3)
print("\nResolution") print("\nResolution")
print(" Native: " + str(height) + "x" + str(width)) print(" Native: %dx%d" % (height, width))
print(" Used: " + str(scale_height) + "x" + str(scale_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 # 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("\nFrames searched: %d (%.2f fps)" % (frames, frames / (timings[4] - timings[3])))
print("Dark frames ignored: " + str(dark_tries)) print("Dark frames ignored: %d " % (dark_tries, ))
print("Certainty of winning frame: " + str(round(match * 10, 3))) print("Certainty of winning frame: %.3f" % (match * 10, ))
# Catch older 3-encoding models # Catch older 3-encoding models
if not match_index in models: if not match_index in models:
match_index = 0 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 # End peacefully
stop(0) stop(0)

View file

@ -16,11 +16,11 @@ def doAuth(pamh):
"""Starts authentication in a seperate process""" """Starts authentication in a seperate process"""
# Abort is Howdy is disabled # Abort is Howdy is disabled
if config.get("core", "disabled") == "true": if config.getboolean("core", "disabled"):
sys.exit(0) sys.exit(0)
# Abort if we're in a remote SSH env # 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: if "SSH_CONNECTION" in os.environ or "SSH_CLIENT" in os.environ or "SSHD_OPTS" in os.environ:
sys.exit(0) sys.exit(0)
@ -29,7 +29,7 @@ def doAuth(pamh):
# Status 10 means we couldn't find any face models # Status 10 means we couldn't find any face models
if status == 10: 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")) pamh.conversation(pamh.Message(pamh.PAM_ERROR_MSG, "No face model known"))
return pamh.PAM_USER_UNKNOWN return pamh.PAM_USER_UNKNOWN
# Status 11 means we exceded the maximum retry count # Status 11 means we exceded the maximum retry count
@ -39,11 +39,11 @@ def doAuth(pamh):
# Status 0 is a successful exit # Status 0 is a successful exit
if status == 0: if status == 0:
# Show the success message if it isn't suppressed # 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())) pamh.conversation(pamh.Message(pamh.PAM_TEXT_INFO, "Identified face as " + pamh.get_user()))
# Try to dismiss the lock screen if enabled # 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 # 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"]) subprocess.Popen(["sudo", "timeout", "1", "loginctl", "unlock-sessions", "--no-ask-password"])