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 sys
import os
import subprocess
import getpass
import argparse
import builtins
@ -16,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

View file

@ -1,14 +1,13 @@
# Save the face of the user in encoded form
# Import required modules
import subprocess
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
@ -56,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 + "]: ")
@ -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()
@ -117,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)

View file

@ -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__))
@ -21,15 +18,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 +47,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 +65,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 +115,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 +133,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:

View file

@ -12,7 +12,6 @@ import cv2
import sys
import os
import json
import math
import configparser
# Read config from disk
@ -43,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())
@ -61,16 +59,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 +88,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 +114,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,31 +149,31 @@ 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(" %s: %dms" % (label, round((timings[1 + offset] - timings[offset]) * 1000)))
print("Time spend")
print("Time spent")
print_timing("Starting up", 0)
print_timing("Opening the camera", 1)
print_timing("Importing face_recognition", 2)
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)

View file

@ -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"])