Skip to content

Commit

Permalink
Merge pull request #178 from boltgolt/dev
Browse files Browse the repository at this point in the history
Version 2.5.1
  • Loading branch information
boltgolt authored Mar 29, 2019
2 parents 983ddb8 + a53530e commit 8f21711
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 37 deletions.
11 changes: 11 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
howdy (2.5.1) xenial; urgency=medium

* Removed dismiss_lockscreen as it could lock users out of their system (thanks @ujjwalbe, @ju916 and many others!)
* Added option to disable howdy when the laptop lid is closed (thanks @accek!)
* Added automatic fallback to default frame color palette (thanks @Ethiarpus!)
* Added manual exposure setting (thanks @accek!)
* Fixed test command ignoring dark frame threshold (thanks @eduncan911!)
* Fixed import error in v4l2 recorder (thanks @timwelch!)

-- boltgolt <[email protected]> Fri, 29 Mar 2019 23:02:21 +0100

howdy (2.5.0) xenial; urgency=medium

* Added FFmpeg and v4l2 recorders (thanks @timwelch!)
Expand Down
25 changes: 7 additions & 18 deletions debian/postinst
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ if not os.path.exists("/tmp/howdy_picked_device"):
if key == "timout":
key = "timeout"

# MIGRATION 2.5.0 -> 2.5.1
# Remove unsafe automatic dismissal of lock screen
if key == "dismiss_lockscreen":
if value == "true":
print("DEPRECATION: Config falue dismiss_lockscreen is no longer supported because of login loop issues.")
continue

try:
newConf.set(section, key, value)
# Add a new section where needed
Expand Down Expand Up @@ -152,24 +159,6 @@ log("Building dlib")

cmd = ["sudo", "python3", "setup.py", "install"]
cuda_used = False
flags = ""

# Get the CPU details
with open("/proc/cpuinfo") as info:
for line in info:
if "flags" in line:
flags = line
break

# Use the most efficient instruction set the CPU supports
if "avx" in flags:
cmd += ["--yes", "USE_AVX_INSTRUCTIONS"]
elif "sse4" in flags:
cmd += ["--yes", "USE_SSE4_INSTRUCTIONS"]
elif "sse3" in flags:
cmd += ["--yes", "USE_SSE3_INSTRUCTIONS"]
elif "sse2" in flags:
cmd += ["--yes", "USE_SSE2_INSTRUCTIONS"]

# Compile and link dlib
try:
Expand Down
2 changes: 1 addition & 1 deletion debian/prerm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ from shutil import rmtree
if "remove" not in sys.argv and "purge" not in sys.argv:
sys.exit(0)

# Don't try running this if it's already gome
# Don't try running this if it's already gone
if not os.path.exists("/lib/security/howdy/cli"):
sys.exit(0)

Expand Down
35 changes: 28 additions & 7 deletions src/cli/test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Show a windows with the video stream and testing information
# Show a window with the video stream and testing information

# Import required modules
import configparser
Expand Down Expand Up @@ -37,6 +37,10 @@
if fh != -1:
video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, fh)

# Read exposure and dark_thresholds from config to use in the main loop
exposure = config.getint("video", "exposure", fallback=-1)
dark_threshold = config.getfloat("video", "dark_threshold")

# Let the user know what's up
print("""
Opening a window with a test feed
Expand Down Expand Up @@ -106,7 +110,17 @@ def print_text(line_number, text):

# Grab a single frame of video
ret, frame = video_capture.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

try:
# Convert from color to grayscale
# First processing of frame, so frame errors show up here
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
except RuntimeError:
pass
except cv2.error:
print("\nUnknown camera, please check your 'device_path' config value.\n")
raise

frame = clahe.apply(frame)
# Make a frame to put overlays in
overlay = frame.copy()
Expand All @@ -133,9 +147,6 @@ def print_text(line_number, text):
# Draw the bar in green
cv2.rectangle(overlay, p1, p2, (0, 200, 0), thickness=cv2.FILLED)

# Draw a stripe indicating the dark threshold
cv2.rectangle(overlay, (8, 35), (20, 36), (255, 0, 0), thickness=cv2.FILLED)

# Print the statis in the bottom left
print_text(0, "RESOLUTION: %dx%d" % (height, width))
print_text(1, "FPS: %d" % (fps, ))
Expand All @@ -147,7 +158,7 @@ def print_text(line_number, text):
cv2.putText(overlay, "SLOW MODE", (width - 66, height - 10), cv2.FONT_HERSHEY_SIMPLEX, .3, (0, 0, 255), 0, cv2.LINE_AA)

# Ignore dark frames
if hist_perc[0] > 50:
if hist_perc[0] > dark_threshold:
# Show that this is an ignored frame in the top right
cv2.putText(overlay, "DARK FRAME", (width - 68, 16), cv2.FONT_HERSHEY_SIMPLEX, .3, (0, 0, 255), 0, cv2.LINE_AA)
else:
Expand All @@ -156,7 +167,8 @@ def print_text(line_number, text):

rec_tm = time.time()
# Get the locations of all faces and their locations
face_locations = face_detector(frame, 1) # upsample 1 time
# Upsample it once
face_locations = face_detector(frame, 1)
rec_tm = time.time() - rec_tm

# Loop though all faces and paint a circle around them
Expand Down Expand Up @@ -193,6 +205,15 @@ def print_text(line_number, text):
if slow_mode:
time.sleep(.5 - frame_time)

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.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 1 = Manual
video_capture.set(cv2.CAP_PROP_EXPOSURE, float(exposure))

# On ctrl+C
except KeyboardInterrupt:
# Let the user know we're stopping
Expand Down
18 changes: 18 additions & 0 deletions src/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ def stop(status):
# This will let the camera adjust its light levels while we're importing for faster scanning
video_capture.grab()

# 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"]

Expand Down Expand Up @@ -180,10 +183,16 @@ def stop(status):
# Grab a single frame of video
ret, frame = video_capture.read()

if frames == 1 and ret is False:
print("Could not read from camera")
exit(12)

try:
# Convert from color to grayscale
# First processing of frame, so frame errors show up here
gsframe = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
except RuntimeError:
gsframe = frame
except cv2.error:
print("\nUnknown camera, please check your 'device_path' config value.\n")
raise
Expand Down Expand Up @@ -261,3 +270,12 @@ def print_timing(label, k):

# End peacefully
stop(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.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 1 = Manual
video_capture.set(cv2.CAP_PROP_EXPOSURE, float(exposure))
12 changes: 8 additions & 4 deletions src/config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ suppress_unknown = false
# Disable Howdy in remote shells
ignore_ssh = true

# Auto dismiss lock screen on confirmation
# Will run loginctl unlock-sessions after every auth
# Experimental, can behave incorrectly on some systems
dismiss_lockscreen = false
# Disable Howdy if lid is closed
ignore_closed_lid = true

# Disable howdy in the PAM
# The howdy command will still function
Expand Down Expand Up @@ -70,6 +68,12 @@ device_format = v4l2
# OPENCV only.
force_mjpeg = false

# Specify exposure value explicitly. This disables autoexposure.
# Use qv4l2 to determine an appropriate value.
# OPENCV only.
exposure = -1

[debug]
# Show a short but detailed diagnostic report in console
# Enabling this can cause some UI apps to fail, only enable it to debug
end_report = false
13 changes: 7 additions & 6 deletions src/pam.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import subprocess
import sys
import os
import glob

# pam-python is running python 2, so we use the old module here
import ConfigParser
Expand All @@ -25,8 +26,13 @@ def doAuth(pamh):
if "SSH_CONNECTION" in os.environ or "SSH_CLIENT" in os.environ or "SSHD_OPTS" in os.environ:
sys.exit(0)

# Abort if lid is closed
if config.getboolean("core", "ignore_closed_lid"):
if any("closed" in open(f).read() for f in glob.glob("/proc/acpi/button/lid/*/state")):
sys.exit(0)

# Alert the user that we are doing face detection
if config.get("core", "detection_notice") == "true":
if config.getboolean("core", "detection_notice"):
pamh.conversation(pamh.Message(pamh.PAM_TEXT_INFO, "Attempting face detection"))

# Run compare as python3 subprocess to circumvent python version and import issues
Expand All @@ -50,11 +56,6 @@ def doAuth(pamh):
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"):
# 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"])

return pamh.PAM_SUCCESS

# Otherwise, we can't discribe what happend but it wasn't successful
Expand Down
2 changes: 1 addition & 1 deletion src/recorders/pyv4l2_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from cv2 import cvtColor, COLOR_GRAY2BGR, CAP_PROP_FRAME_WIDTH, CAP_PROP_FRAME_HEIGHT

try:
from v4l2.frame import Frame
from pyv4l2.frame import Frame
except ImportError:
print("Missing pyv4l2 module, please run:")
print(" pip3 install pyv4l2\n")
Expand Down

0 comments on commit 8f21711

Please sign in to comment.