期间需要安装一些东西,镜像在国外,下载得很慢,甚至安装失败
sudo add-apt-repository ppa:boltgolt/howdy
sudo apt update
sudo apt install howdy
安装时会出现f/b/s
三个选项,fast/balance/security
分别表示识别快、平衡、安全
,根据需要选择
#安装v4l-utils,用于检测摄像头设备
sudo apt-get install v4l-utils
#查看摄像头设备,一般/dev/video0就是摄像头设备
v4l2-ctl --list-devices
#修改howdy的配置文件
sudo vim /lib/security/howdy/config.ini
#将device_path修改为/dev/video0
device_path = /dev/video0
sudo howdy add
# 输入一个24字符以内的标签用于区分,然后会自动打开摄像头进行人脸扫描,完成之后提示Scan complete
完成第四步就已经可以人脸使用sudo
了,但锁屏还不能使用
sudo chmod 777 -R /lib/security/howdy
若不能解决
cd /lib/security/howdy
sudo vim compare.py
将compare.py
内容替换为
# Compare incomming video with known faces
# Running in a local python instance to get around PATH issues
# Import time so we can start timing asap
import time
# Start timing
timings = {
"st": time.time()
}
# Import required modules
import sys
# Some user libraries will make howdy dosn't work
sys.path.append("/lib/security/howdy/")
for path in range(len(sys.path)):
if len(sys.path[path])>5 and sys.path[path][:5]=="/home":
sys.path[path]=""
import os
import json
import configparser
import dlib
import cv2
import datetime
import atexit
import subprocess
import snapshot
import numpy as np
import _thread as thread
from i18n import _
from recorders.video_capture import VideoCapture
def exit(code=None):
"""Exit while closeing howdy-gtk properly"""
global gtk_proc
# Exit the auth ui process if there is one
if "gtk_proc" in globals():
gtk_proc.terminate()
# Exit compare
if code is not None:
sys.exit(code)
def init_detector(lock):
"""Start face detector, encoder and predictor in a new thread"""
global face_detector, pose_predictor, face_encoder
# Test if at lest 1 of the data files is there and abort if it's not
if not os.path.isfile(PATH + "/dlib-data/shape_predictor_5_face_landmarks.dat"):
print(_("Data files have not been downloaded, please run the following commands:"))
print("\n\tcd " + PATH + "/dlib-data")
print("\tsudo ./install.sh\n")
lock.release()
exit(1)
# 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")
else:
face_detector = dlib.get_frontal_face_detector()
# 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")
# Note the time it took to initialize detectors
timings["ll"] = time.time() - timings["ll"]
lock.release()
def make_snapshot(type):
"""Generate snapshot after detection"""
snapshot.generate(snapframes, [
type + _(" LOGIN"),
_("Date: ") + datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S UTC"),
_("Scan time: ") + str(round(time.time() - timings["fr"], 2)) + "s",
_("Frames: ") + str(frames) + " (" + str(round(frames / (time.time() - timings["fr"]), 2)) + "FPS)",
_("Hostname: ") + os.uname().nodename,
_("Best certainty value: ") + str(round(lowest_certainty * 10, 1))
])
def send_to_ui(type, message):
"""Send message to the auth ui"""
global gtk_proc
# Only execute of the proccess started
if "gtk_proc" in globals():
# Format message so the ui can parse it
message = type + "=" + message + " \n"
# Try to send the message to the auth ui, but it's okay if that fails
try:
gtk_proc.stdin.write(bytearray(message.encode("utf-8")))
gtk_proc.stdin.flush()
except IOError:
pass
# Make sure we were given an username to tast against
if len(sys.argv) < 2:
exit(12)
# Get the absolute path to the current directory
PATH = os.path.abspath(__file__ + "/..")
# The username of the user being authenticated
user = sys.argv[1]
# The model file contents
models = []
# Encoded face models
encodings = []
# Amount of ignored 100% black frames
black_tries = 0
# Amount of ingnored dark frames
dark_tries = 0
# Total amount of frames captured
frames = 0
# Captured frames for snapshot capture
snapframes = []
# Tracks the lowest certainty value in the loop
lowest_certainty = 10
# Face recognition/detection instances
face_detector = None
pose_predictor = None
face_encoder = None
# Try to load the face model from the models folder
try:
models = json.load(open(PATH + "/models/" + user + ".dat"))
for model in models:
encodings += model["data"]
except FileNotFoundError:
exit(10)
# Check if the file contains a model
if len(models) < 1:
exit(10)
# Read config from disk
config = configparser.ConfigParser()
config.read(PATH + "/config.ini")
# Get all config values needed
use_cnn = config.getboolean("core", "use_cnn", fallback=False)
timeout = config.getint("video", "timeout", 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)
capture_failed = config.getboolean("snapshots", "capture_failed", fallback=False)
capture_successful = config.getboolean("snapshots", "capture_successful", fallback=False)
gtk_stdout = config.getboolean("debug", "gtk_stdout", fallback=False)
# Send the gtk outupt to the terminal if enabled in the config
gtk_pipe = sys.stdout if gtk_stdout else subprocess.DEVNULL
# Start the auth ui, register it to be always be closed on exit
try:
gtk_proc = subprocess.Popen(["../howdy-gtk/src/init.py", "--start-auth-ui"], stdin=subprocess.PIPE, stdout=gtk_pipe, stderr=gtk_pipe)
atexit.register(exit)
except FileNotFoundError:
pass
# Write to the stdin to redraw ui
send_to_ui("M", _("Starting up..."))
# Save the time needed to start the script
timings["in"] = time.time() - timings["st"]
# Import face recognition, takes some 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()
video_capture = VideoCapture(config)
# Read exposure from config to use in the main loop
exposure = config.getint("video", "exposure", fallback=-1)
# Note the time it took to open the camera
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
height = video_capture.internal.get(cv2.CAP_PROP_FRAME_HEIGHT) or 1
# Calculate the amount the image has to shrink
scaling_factor = (max_height / height) or 1
# Fetch config settings out of the loop
timeout = config.getint("video", "timeout")
dark_threshold = config.getfloat("video", "dark_threshold")
end_report = config.getboolean("debug", "end_report")
# Initiate histogram equalization
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
# Let the ui know that we're ready
send_to_ui("M", _("Identifying you..."))
# Start the read loop
frames = 0
valid_frames = 0
timings["fr"] = time.time()
dark_running_total = 0
while True:
# Increment the frame count every loop
frames += 1
# Form a string to let the user know we're real busy
ui_subtext = "Scanned " + str(valid_frames - dark_tries) + " frames"
if (dark_tries > 1):
ui_subtext += " (skipped " + str(dark_tries) + " dark frames)"
# Show it in the ui as subtext
send_to_ui("S", ui_subtext)
# Stop if we've exceded the time limit
if time.time() - timings["fr"] > timeout:
# Create a timeout snapshot if enabled
if capture_failed:
make_snapshot(_("FAILED"))
if dark_tries == valid_frames:
print(_("All frames were too dark, please check dark_threshold in config"))
print(_("Average darkness: {avg}, Threshold: {threshold}").format(avg=str(dark_running_total / max(1, valid_frames)), threshold=str(dark_threshold)))
exit(13)
else:
exit(11)
# Grab a single frame of video
frame, gsframe = video_capture.read_frame()
gsframe = clahe.apply(gsframe)
# If snapshots have been turned on
if capture_failed or capture_successful:
# Start capturing frames for the snapshot
if len(snapframes) < 3:
snapframes.append(frame)
# Create a histogram of the image with 8 values
hist = cv2.calcHist([gsframe], [0], None, [8], [0, 256])
# All values combined for percentage calculation
hist_total = np.sum(hist)
# Calculate frame darkness
darkness = (hist[0] / hist_total * 100)
# If the image is fully black due to a bad camera read,
# skip to the next frame
if (hist_total == 0) or (darkness == 100):
black_tries += 1
continue
dark_running_total += darkness
valid_frames += 1
# If the image exceeds darkness threshold due to subject distance,
# skip to the next frame
if (darkness > dark_threshold):
dark_tries += 1
continue
# If the hight is too high
if scaling_factor != 1:
# Apply that factor to the frame
frame = cv2.resize(frame, 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
# 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))
# Match this found face against a known face
matches = np.linalg.norm(encodings - face_encoding, axis=1)
# Get best match
match_index = np.argmin(matches)
match = matches[match_index]
# Update certainty if we have a new low
if lowest_certainty > match:
lowest_certainty = match
# Check if a match that's confident enough
if 0 < match < video_certainty:
timings["tt"] = time.time() - timings["st"]
timings["fl"] = time.time() - timings["fr"]
# If set to true in the config, print debug text
if end_report:
def print_timing(label, k):
"""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"), "fl")
print_timing(_("Total time"), "tt")
print(_("\nResolution"))
width = video_capture.fw or 1
print(_(" Native: %dx%d") % (height, width))
# Save the new size for diagnostics
scale_height, scale_width = frame.shape[:2]
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["fl"]))
print(_("Black frames ignored: %d ") % (black_tries, ))
print(_("Dark frames ignored: %d ") % (dark_tries, ))
print(_("Certainty of winning frame: %.3f") % (match * 10, ))
print(_("Winning model: %d (\"%s\")") % (match_index, models[match_index]["label"]))
# Make snapshot if enabled
if capture_successful:
make_snapshot(_("SUCCESSFUL"))
# Run rubberstamps if enabled
if config.getboolean("rubberstamps", "enabled", fallback=False):
import rubberstamps
send_to_ui("S", "")
if "gtk_proc" not in vars():
gtk_proc = None
rubberstamps.execute(config, gtk_proc, {
"video_capture": video_capture,
"face_detector": face_detector,
"pose_predictor": pose_predictor,
"clahe": clahe
})
# End peacefully
exit(0)
if exposure != -1:
# For a strange reason on some cameras (e.g. Lenoxo X1E) setting manual exposure works only after a couple frames
# are captured and even after a delay it does not always work. Setting exposure at every frame is reliable though.
video_capture.internal.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 1 = Manual
video_capture.internal.set(cv2.CAP_PROP_EXPOSURE, float(exposure))
并新建i18n.py
# Support file for translations
# Import modules
import gettext
import os
# Get the right translation based on locale, falling back to base if none found
translation = gettext.translation("core", localedir=os.path.join(os.path.dirname(__file__), 'locales'), fallback=True)
translation.install()
# Export translation function as _
_ = translation.gettext
sudo howdy disable 1
sudo howdy disable 0
howdy
常用命令:
sudo howdy list:面部模型记录
sudo howdy remove face_ID:删除指定ID的面部记录
sudo howdy clear:清除所有面部模型记录
sudo howdy disable 1:禁用howdy功能
sudo howdy disable 0:启用howdy功能