From 2917e8ada4f04a01f11691081374150469eb32fe Mon Sep 17 00:00:00 2001 From: boltgolt Date: Wed, 2 Jan 2019 23:36:09 +0100 Subject: [PATCH] Code cleanup --- debian/postinst | 75 +++++++++++++++++++++++++++---------------------- debian/preinst | 3 +- src/cli.py | 2 +- src/compare.py | 71 +++++++++++++++++++++++----------------------- 4 files changed, 81 insertions(+), 70 deletions(-) diff --git a/debian/postinst b/debian/postinst index 91afe47..f3dd041 100755 --- a/debian/postinst +++ b/debian/postinst @@ -38,6 +38,7 @@ def handleStatus(status): sys.exit(1) +# Create shorthand for subprocess creation sc = subprocess.call # We're not in fresh configuration mode so don't continue the setup @@ -98,79 +99,88 @@ handleStatus(sc(["pip3", "install", "--no-cache-dir", "--upgrade", "pip"])) log("Downloading and unpacking data files") +# Run the bash script to download and unpack the .dat files needed handleStatus(subprocess.call(["./install.sh"], shell=True, cwd="/lib/security/howdy/dlib-data")) -log('Downloading dlib') +log("Downloading dlib") -dlib_archive = '/tmp/v19.16.tar.gz' - -loader = which('curl') +dlib_archive = "/tmp/v19.16.tar.gz" +loader = which("curl") LOADER_CMD = None + +# If curl is installed, use that as the downloader if loader: - LOADER_CMD = [loader, '--retry', '5', '--location', '--output'] + LOADER_CMD = [loader, "--retry", "5", "--location", "--output"] +# Otherwise, fall back on wget else: - loader = which('wget') - LOADER_CMD = [loader, '--tries', '5', '--output-document'] - -cmd = LOADER_CMD + [dlib_archive, 'https://github.com/davisking/dlib/archive/v19.16.tar.gz'] + loader = which("wget") + LOADER_CMD = [loader, "--tries", "5", "--output-document"] +# Assemble and execute the download command +cmd = LOADER_CMD + [dlib_archive, "https://github.com/davisking/dlib/archive/v19.16.tar.gz"] handleStatus(sc(cmd)) +# The folder containing the dlib source DLIB_DIR = None - +# A regex of all files to ignore while unpacking the archive excludes = re.compile( - 'davisking-dlib-\w+/(dlib/(http_client|java|matlab|test/)|' - '(docs|examples|python_examples)|' - 'tools/(archive|convert_dlib_nets_to_caffe|htmlify|imglab|python/test|visual_studio_natvis))' + "davisking-dlib-\w+/(dlib/(http_client|java|matlab|test/)|" + "(docs|examples|python_examples)|" + "tools/(archive|convert_dlib_nets_to_caffe|htmlify|imglab|python/test|visual_studio_natvis))" ) +# Open the archive with tarfile.open(dlib_archive) as tf: for item in tf: - # tarball contains directory davisking-dlib-, so peek into archive for the name + # Set the destenation dir if unset if not DLIB_DIR: DLIB_DIR = "/tmp/" + item.name # extract only files sufficient for building if not excludes.match(item.name): - tf.extract(item, '/tmp') + tf.extract(item, "/tmp") +# Delete the downloaded archive os.unlink(dlib_archive) log("Building dlib") -# Start the build cmd = ["sudo", "python3", "setup.py", "install"] cuda_used = False +flags = "" -flags = '' -with open('/proc/cpuinfo') as info: +# Get the CPU details +with open("/proc/cpuinfo") as info: for line in info: - if 'flags' in line: + if "flags" in line: flags = line break -if 'avx' in flags: +# Use the most efficient instruction set the CPU supports +if "avx" in flags: cmd += ["--yes", "USE_AVX_INSTRUCTIONS"] -elif 'sse4' in flags: +elif "sse4" in flags: cmd += ["--yes", "USE_SSE4_INSTRUCTIONS"] -elif 'sse3' in flags: +elif "sse3" in flags: cmd += ["--yes", "USE_SSE3_INSTRUCTIONS"] -elif 'sse2' in flags: +elif "sse2" in flags: cmd += ["--yes", "USE_SSE2_INSTRUCTIONS"] +# Compile and link dlib try: sp = subprocess.Popen(cmd, cwd=DLIB_DIR, stdout=subprocess.PIPE) except subprocess.CalledProcessError: print("Error while building dlib") raise +# Go through each line from stdout while sp.poll() is None: line = sp.stdout.readline().decode("utf-8") - if 'DLIB WILL USE CUDA' in line: + if "DLIB WILL USE CUDA" in line: cuda_used = True - print(line, end='') + print(line, end="") log("Cleaning up dlib") @@ -188,20 +198,19 @@ log("Configuring howdy") # Manually change the camera id to the one picked for line in fileinput.input(["/lib/security/howdy/config.ini"], inplace=1): - print( - line - .replace("device_path = none", "device_path = " + picked) - .replace("use_cnn = false", "use_cnn = " + str(cuda_used).lower()), - end="" - ) + line = line.replace("device_path = none", "device_path = " + picked) + line = line.replace("use_cnn = false", "use_cnn = " + str(cuda_used).lower()) + + print(line, end="") + print("Camera ID saved") # Secure the howdy folder handleStatus(sc(["chmod 744 -R /lib/security/howdy/"], shell=True)) # Allow anyone to execute the python CLI -os.chmod('/lib/security/howdy', 0o755) -os.chmod('/lib/security/howdy/cli.py', 0o755) +os.chmod("/lib/security/howdy", 0o755) +os.chmod("/lib/security/howdy/cli.py", 0o755) handleStatus(sc(["chmod 755 -R /lib/security/howdy/cli"], shell=True)) print("Permissions set") diff --git a/debian/preinst b/debian/preinst index 4acfb39..e355a15 100755 --- a/debian/preinst +++ b/debian/preinst @@ -9,6 +9,7 @@ def col(id): if id == 3: return "\033[31m" return "\033[0m" + import subprocess import time import sys @@ -24,7 +25,7 @@ if "upgrade" in sys.argv: # Let the user know so he knows where to look on a failed install print("Backup of Howdy config file created in /tmp/howdy_config_backup_v" + sys.argv[2] + ".ini") - except e: + except subprocess.CalledProcessError: print("Could not make an backup of old Howdy config file") # Don't continue setup when we're just upgrading diff --git a/src/cli.py b/src/cli.py index 07447cf..5906f4d 100755 --- a/src/cli.py +++ b/src/cli.py @@ -11,7 +11,7 @@ import builtins # Try to get the original username (not "root") from shell try: user = os.getlogin() -except: +except Exception: user = os.environ.get("SUDO_USER") # If that fails, try to get the direct user diff --git a/src/compare.py b/src/compare.py index 7fc9c87..9aefb5d 100644 --- a/src/compare.py +++ b/src/compare.py @@ -6,7 +6,7 @@ import time # Start timing timings = { - 'st': time.time() + "st": time.time() } # Import required modules @@ -21,23 +21,21 @@ import _thread as thread def init_detector(lock): + """Start face detector, encoder and predictor in a new thread""" global face_detector, pose_predictor, face_encoder + + # Use the CNN detector if enabled if use_cnn: - face_detector = dlib.cnn_face_detection_model_v1( - PATH + '/dlib-data/mmod_human_face_detector.dat' - ) + face_detector = dlib.cnn_face_detection_model_v1(PATH + "/dlib-data/mmod_human_face_detector.dat") else: face_detector = dlib.get_frontal_face_detector() - pose_predictor = dlib.shape_predictor( - PATH + '/dlib-data/shape_predictor_5_face_landmarks.dat' - ) + # Start the others regardless + pose_predictor = dlib.shape_predictor(PATH + "/dlib-data/shape_predictor_5_face_landmarks.dat") + face_encoder = dlib.face_recognition_model_v1(PATH + "/dlib-data/dlib_face_recognition_resnet_model_v1.dat") - face_encoder = dlib.face_recognition_model_v1( - PATH + '/dlib-data/dlib_face_recognition_resnet_model_v1.dat' - ) # Note the time it took to initialize detectors - timings['ll'] = time.time() - timings['ll'] + timings["ll"] = time.time() - timings["ll"] lock.release() @@ -52,7 +50,7 @@ if len(sys.argv) < 2: sys.exit(12) # Get the absolute path to the current directory -PATH = os.path.abspath(__file__ + '/..') +PATH = os.path.abspath(__file__ + "/..") # The username of the user being authenticated user = sys.argv[1] @@ -86,25 +84,26 @@ if len(models) < 1: config = configparser.ConfigParser() config.read(PATH + "/config.ini") -# CNN usage flag -use_cnn = config.getboolean('core', 'use_cnn', fallback=False) +# Get all config values needed +use_cnn = config.getboolean("core", "use_cnn", fallback=False) timeout = config.getint("video", "timout", fallback=5) dark_threshold = config.getfloat("video", "dark_threshold", fallback=50.0) video_certainty = config.getfloat("video", "certainty", fallback=3.5) / 10 end_report = config.getboolean("debug", "end_report", fallback=False) # Save the time needed to start the script -timings['in'] = time.time() - timings['st'] +timings["in"] = time.time() - timings["st"] # Import face recognition, takes some time -timings['ll'] = time.time() +timings["ll"] = time.time() +# Start threading and wait for init to finish lock = thread.allocate_lock() lock.acquire() thread.start_new_thread(init_detector, (lock, )) # Start video capture on the IR camera -timings['ic'] = time.time() +timings["ic"] = time.time() # Check if the user explicitly set ffmpeg as recorder if config.get("video", "recording_plugin") == "ffmpeg": @@ -120,7 +119,8 @@ else: # Force MJPEG decoding if true if config.getboolean("video", "force_mjpeg", fallback=False): # Set a magic number, will enable MJPEG but is badly documented - video_capture.set(cv2.CAP_PROP_FOURCC, 1196444237) # 1196444237 is 'GPJM' in ASCII + # 1196444237 is "GPJM" in ASCII + video_capture.set(cv2.CAP_PROP_FOURCC, 1196444237) # Set the frame width and height if requested fw = config.getint("video", "frame_width", fallback=-1) @@ -135,14 +135,13 @@ if fh != -1: video_capture.grab() # Note the time it took to open the camera -timings['ic'] = time.time() - timings['ic'] +timings["ic"] = time.time() - timings["ic"] # wait for thread to finish lock.acquire() lock.release() del lock - # Fetch the max frame height max_height = config.getfloat("video", "max_height", fallback=0.0) # Get the height of the image @@ -158,14 +157,14 @@ end_report = config.getboolean("debug", "end_report") # Start the read loop frames = 0 -timings['fr'] = time.time() +timings["fr"] = time.time() while True: # Increment the frame count every loop frames += 1 # Stop if we've exceded the time limit - if time.time() - timings['fr'] > timeout: + if time.time() - timings["fr"] > timeout: stop(11) # Grab a single frame of video @@ -190,17 +189,18 @@ while True: gsframe = cv2.resize(gsframe, None, fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_AREA) # Get all faces from that frame as encodings - face_locations = face_detector(gsframe, 1) # upsample 1 time + # Upsamples 1 time + face_locations = face_detector(gsframe, 1) # Loop through each face for fl in face_locations: if use_cnn: fl = fl.rect + # Fetch the faces in the image face_landmark = pose_predictor(frame, fl) - face_encoding = np.array( - face_encoder.compute_face_descriptor(frame, face_landmark, 1) # num_jitters=1 - ) + face_encoding = np.array(face_encoder.compute_face_descriptor(frame, face_landmark, 1)) + # Match this found face against a known face matches = np.linalg.norm(encodings - face_encoding, axis=1) @@ -210,8 +210,8 @@ while True: # Check if a match that's confident enough if 0 < match < video_certainty: - timings['tt'] = time.time() - timings['st'] - timings['fr'] = time.time() - timings['fr'] + timings["tt"] = time.time() - timings["st"] + timings["fr"] = time.time() - timings["fr"] # If set to true in the config, print debug text if end_report: @@ -219,13 +219,14 @@ while True: """Helper function to print a timing from the list""" print(" %s: %dms" % (label, round(timings[k] * 1000))) + # Print a nice timing report print("Time spent") - print_timing("Starting up", 'in') - print(" Open cam + load libs: %dms" % (round(max(timings['ll'], timings['ic']) * 1000, ))) - print_timing(" Opening the camera", 'ic') - print_timing(" Importing recognition libs", 'll') - print_timing("Searching for known face", 'fr') - print_timing("Total time", 'tt') + print_timing("Starting up", "in") + print(" Open cam + load libs: %dms" % (round(max(timings["ll"], timings["ic"]) * 1000, ))) + print_timing(" Opening the camera", "ic") + print_timing(" Importing recognition libs", "ll") + print_timing("Searching for known face", "fr") + print_timing("Total time", "tt") print("\nResolution") width = video_capture.get(cv2.CAP_PROP_FRAME_WIDTH) or 1 @@ -235,7 +236,7 @@ while True: 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: %d (%.2f fps)" % (frames, frames / timings['fr'])) + print("\nFrames searched: %d (%.2f fps)" % (frames, frames / timings["fr"])) print("Dark frames ignored: %d " % (dark_tries, )) print("Certainty of winning frame: %.3f" % (match * 10, ))