Code cleanup

This commit is contained in:
boltgolt 2019-01-02 23:36:09 +01:00
parent e38422c8a0
commit 2917e8ada4
No known key found for this signature in database
GPG key ID: BECEC9937E1AAE26
4 changed files with 81 additions and 70 deletions

75
debian/postinst vendored
View file

@ -38,6 +38,7 @@ def handleStatus(status):
sys.exit(1) sys.exit(1)
# Create shorthand for subprocess creation
sc = subprocess.call sc = subprocess.call
# We're not in fresh configuration mode so don't continue the setup # 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") 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")) 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' dlib_archive = "/tmp/v19.16.tar.gz"
loader = which("curl")
loader = which('curl')
LOADER_CMD = None LOADER_CMD = None
# If curl is installed, use that as the downloader
if loader: if loader:
LOADER_CMD = [loader, '--retry', '5', '--location', '--output'] LOADER_CMD = [loader, "--retry", "5", "--location", "--output"]
# Otherwise, fall back on wget
else: else:
loader = which('wget') loader = which("wget")
LOADER_CMD = [loader, '--tries', '5', '--output-document'] LOADER_CMD = [loader, "--tries", "5", "--output-document"]
cmd = LOADER_CMD + [dlib_archive, 'https://github.com/davisking/dlib/archive/v19.16.tar.gz']
# Assemble and execute the download command
cmd = LOADER_CMD + [dlib_archive, "https://github.com/davisking/dlib/archive/v19.16.tar.gz"]
handleStatus(sc(cmd)) handleStatus(sc(cmd))
# The folder containing the dlib source
DLIB_DIR = None DLIB_DIR = None
# A regex of all files to ignore while unpacking the archive
excludes = re.compile( excludes = re.compile(
'davisking-dlib-\w+/(dlib/(http_client|java|matlab|test/)|' "davisking-dlib-\w+/(dlib/(http_client|java|matlab|test/)|"
'(docs|examples|python_examples)|' "(docs|examples|python_examples)|"
'tools/(archive|convert_dlib_nets_to_caffe|htmlify|imglab|python/test|visual_studio_natvis))' "tools/(archive|convert_dlib_nets_to_caffe|htmlify|imglab|python/test|visual_studio_natvis))"
) )
# Open the archive
with tarfile.open(dlib_archive) as tf: with tarfile.open(dlib_archive) as tf:
for item in tf: for item in tf:
# tarball contains directory davisking-dlib-<commit id>, so peek into archive for the name # Set the destenation dir if unset
if not DLIB_DIR: if not DLIB_DIR:
DLIB_DIR = "/tmp/" + item.name DLIB_DIR = "/tmp/" + item.name
# extract only files sufficient for building # extract only files sufficient for building
if not excludes.match(item.name): if not excludes.match(item.name):
tf.extract(item, '/tmp') tf.extract(item, "/tmp")
# Delete the downloaded archive
os.unlink(dlib_archive) os.unlink(dlib_archive)
log("Building dlib") log("Building dlib")
# Start the build
cmd = ["sudo", "python3", "setup.py", "install"] cmd = ["sudo", "python3", "setup.py", "install"]
cuda_used = False cuda_used = False
flags = ""
flags = '' # Get the CPU details
with open('/proc/cpuinfo') as info: with open("/proc/cpuinfo") as info:
for line in info: for line in info:
if 'flags' in line: if "flags" in line:
flags = line flags = line
break break
if 'avx' in flags: # Use the most efficient instruction set the CPU supports
if "avx" in flags:
cmd += ["--yes", "USE_AVX_INSTRUCTIONS"] cmd += ["--yes", "USE_AVX_INSTRUCTIONS"]
elif 'sse4' in flags: elif "sse4" in flags:
cmd += ["--yes", "USE_SSE4_INSTRUCTIONS"] cmd += ["--yes", "USE_SSE4_INSTRUCTIONS"]
elif 'sse3' in flags: elif "sse3" in flags:
cmd += ["--yes", "USE_SSE3_INSTRUCTIONS"] cmd += ["--yes", "USE_SSE3_INSTRUCTIONS"]
elif 'sse2' in flags: elif "sse2" in flags:
cmd += ["--yes", "USE_SSE2_INSTRUCTIONS"] cmd += ["--yes", "USE_SSE2_INSTRUCTIONS"]
# Compile and link dlib
try: try:
sp = subprocess.Popen(cmd, cwd=DLIB_DIR, stdout=subprocess.PIPE) sp = subprocess.Popen(cmd, cwd=DLIB_DIR, stdout=subprocess.PIPE)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
print("Error while building dlib") print("Error while building dlib")
raise raise
# Go through each line from stdout
while sp.poll() is None: while sp.poll() is None:
line = sp.stdout.readline().decode("utf-8") line = sp.stdout.readline().decode("utf-8")
if 'DLIB WILL USE CUDA' in line: if "DLIB WILL USE CUDA" in line:
cuda_used = True cuda_used = True
print(line, end='') print(line, end="")
log("Cleaning up dlib") log("Cleaning up dlib")
@ -188,20 +198,19 @@ log("Configuring howdy")
# Manually change the camera id to the one picked # Manually change the camera id to the one picked
for line in fileinput.input(["/lib/security/howdy/config.ini"], inplace=1): for line in fileinput.input(["/lib/security/howdy/config.ini"], inplace=1):
print( line = line.replace("device_path = none", "device_path = " + picked)
line line = line.replace("use_cnn = false", "use_cnn = " + str(cuda_used).lower())
.replace("device_path = none", "device_path = " + picked)
.replace("use_cnn = false", "use_cnn = " + str(cuda_used).lower()), print(line, end="")
end=""
)
print("Camera ID saved") print("Camera ID saved")
# Secure the howdy folder # Secure the howdy folder
handleStatus(sc(["chmod 744 -R /lib/security/howdy/"], shell=True)) handleStatus(sc(["chmod 744 -R /lib/security/howdy/"], shell=True))
# Allow anyone to execute the python CLI # Allow anyone to execute the python CLI
os.chmod('/lib/security/howdy', 0o755) os.chmod("/lib/security/howdy", 0o755)
os.chmod('/lib/security/howdy/cli.py', 0o755) os.chmod("/lib/security/howdy/cli.py", 0o755)
handleStatus(sc(["chmod 755 -R /lib/security/howdy/cli"], shell=True)) handleStatus(sc(["chmod 755 -R /lib/security/howdy/cli"], shell=True))
print("Permissions set") print("Permissions set")

3
debian/preinst vendored
View file

@ -9,6 +9,7 @@ def col(id):
if id == 3: return "\033[31m" if id == 3: return "\033[31m"
return "\033[0m" return "\033[0m"
import subprocess import subprocess
import time import time
import sys 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 # 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") 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") print("Could not make an backup of old Howdy config file")
# Don't continue setup when we're just upgrading # Don't continue setup when we're just upgrading

View file

@ -11,7 +11,7 @@ import builtins
# Try to get the original username (not "root") from shell # Try to get the original username (not "root") from shell
try: try:
user = os.getlogin() user = os.getlogin()
except: except Exception:
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

View file

@ -6,7 +6,7 @@ import time
# Start timing # Start timing
timings = { timings = {
'st': time.time() "st": time.time()
} }
# Import required modules # Import required modules
@ -21,23 +21,21 @@ import _thread as thread
def init_detector(lock): def init_detector(lock):
"""Start face detector, encoder and predictor in a new thread"""
global face_detector, pose_predictor, face_encoder global face_detector, pose_predictor, face_encoder
# Use the CNN detector if enabled
if use_cnn: if use_cnn:
face_detector = dlib.cnn_face_detection_model_v1( face_detector = dlib.cnn_face_detection_model_v1(PATH + "/dlib-data/mmod_human_face_detector.dat")
PATH + '/dlib-data/mmod_human_face_detector.dat'
)
else: else:
face_detector = dlib.get_frontal_face_detector() face_detector = dlib.get_frontal_face_detector()
pose_predictor = dlib.shape_predictor( # Start the others regardless
PATH + '/dlib-data/shape_predictor_5_face_landmarks.dat' 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 # Note the time it took to initialize detectors
timings['ll'] = time.time() - timings['ll'] timings["ll"] = time.time() - timings["ll"]
lock.release() lock.release()
@ -52,7 +50,7 @@ if len(sys.argv) < 2:
sys.exit(12) sys.exit(12)
# Get the absolute path to the current directory # 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 # The username of the user being authenticated
user = sys.argv[1] user = sys.argv[1]
@ -86,25 +84,26 @@ if len(models) < 1:
config = configparser.ConfigParser() config = configparser.ConfigParser()
config.read(PATH + "/config.ini") config.read(PATH + "/config.ini")
# CNN usage flag # Get all config values needed
use_cnn = config.getboolean('core', 'use_cnn', fallback=False) use_cnn = config.getboolean("core", "use_cnn", fallback=False)
timeout = config.getint("video", "timout", fallback=5) timeout = config.getint("video", "timout", fallback=5)
dark_threshold = config.getfloat("video", "dark_threshold", fallback=50.0) dark_threshold = config.getfloat("video", "dark_threshold", fallback=50.0)
video_certainty = config.getfloat("video", "certainty", fallback=3.5) / 10 video_certainty = config.getfloat("video", "certainty", fallback=3.5) / 10
end_report = config.getboolean("debug", "end_report", fallback=False) end_report = config.getboolean("debug", "end_report", fallback=False)
# Save the time needed to start the script # 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 # 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 = thread.allocate_lock()
lock.acquire() lock.acquire()
thread.start_new_thread(init_detector, (lock, )) thread.start_new_thread(init_detector, (lock, ))
# Start video capture on the IR camera # Start video capture on the IR camera
timings['ic'] = time.time() timings["ic"] = time.time()
# Check if the user explicitly set ffmpeg as recorder # Check if the user explicitly set ffmpeg as recorder
if config.get("video", "recording_plugin") == "ffmpeg": if config.get("video", "recording_plugin") == "ffmpeg":
@ -120,7 +119,8 @@ else:
# Force MJPEG decoding if true # Force MJPEG decoding if true
if config.getboolean("video", "force_mjpeg", fallback=False): if config.getboolean("video", "force_mjpeg", fallback=False):
# Set a magic number, will enable MJPEG but is badly documented # 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 # Set the frame width and height if requested
fw = config.getint("video", "frame_width", fallback=-1) fw = config.getint("video", "frame_width", fallback=-1)
@ -135,14 +135,13 @@ if fh != -1:
video_capture.grab() video_capture.grab()
# Note the time it took to open the camera # 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 # wait for thread to finish
lock.acquire() lock.acquire()
lock.release() lock.release()
del lock del lock
# Fetch the max frame height # Fetch the max frame height
max_height = config.getfloat("video", "max_height", fallback=0.0) max_height = config.getfloat("video", "max_height", fallback=0.0)
# Get the height of the image # Get the height of the image
@ -158,14 +157,14 @@ end_report = config.getboolean("debug", "end_report")
# Start the read loop # Start the read loop
frames = 0 frames = 0
timings['fr'] = time.time() timings["fr"] = time.time()
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['fr'] > timeout: if time.time() - timings["fr"] > timeout:
stop(11) stop(11)
# Grab a single frame of video # 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) gsframe = cv2.resize(gsframe, None, fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_AREA)
# Get all faces from that frame as encodings # 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 # Loop through each face
for fl in face_locations: for fl in face_locations:
if use_cnn: if use_cnn:
fl = fl.rect fl = fl.rect
# Fetch the faces in the image
face_landmark = pose_predictor(frame, fl) face_landmark = pose_predictor(frame, fl)
face_encoding = np.array( face_encoding = np.array(face_encoder.compute_face_descriptor(frame, face_landmark, 1))
face_encoder.compute_face_descriptor(frame, face_landmark, 1) # num_jitters=1
)
# Match this found face against a known face # Match this found face against a known face
matches = np.linalg.norm(encodings - face_encoding, axis=1) matches = np.linalg.norm(encodings - face_encoding, axis=1)
@ -210,8 +210,8 @@ while True:
# Check if a match that's confident enough # Check if a match that's confident enough
if 0 < match < video_certainty: if 0 < match < video_certainty:
timings['tt'] = time.time() - timings['st'] timings["tt"] = time.time() - timings["st"]
timings['fr'] = time.time() - timings['fr'] timings["fr"] = time.time() - timings["fr"]
# If set to true in the config, print debug text # If set to true in the config, print debug text
if end_report: if end_report:
@ -219,13 +219,14 @@ while True:
"""Helper function to print a timing from the list""" """Helper function to print a timing from the list"""
print(" %s: %dms" % (label, round(timings[k] * 1000))) print(" %s: %dms" % (label, round(timings[k] * 1000)))
# Print a nice timing report
print("Time spent") print("Time spent")
print_timing("Starting up", 'in') print_timing("Starting up", "in")
print(" Open cam + load libs: %dms" % (round(max(timings['ll'], timings['ic']) * 1000, ))) print(" Open cam + load libs: %dms" % (round(max(timings["ll"], timings["ic"]) * 1000, )))
print_timing(" Opening the camera", 'ic') print_timing(" Opening the camera", "ic")
print_timing(" Importing recognition libs", 'll') print_timing(" Importing recognition libs", "ll")
print_timing("Searching for known face", 'fr') print_timing("Searching for known face", "fr")
print_timing("Total time", 'tt') print_timing("Total time", "tt")
print("\nResolution") print("\nResolution")
width = video_capture.get(cv2.CAP_PROP_FRAME_WIDTH) or 1 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)) 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: %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("Dark frames ignored: %d " % (dark_tries, ))
print("Certainty of winning frame: %.3f" % (match * 10, )) print("Certainty of winning frame: %.3f" % (match * 10, ))