Skip to content

Commit 8f21711

Browse files
authored
Merge pull request #178 from boltgolt/dev
Version 2.5.1
2 parents 983ddb8 + a53530e commit 8f21711

File tree

8 files changed

+81
-37
lines changed

8 files changed

+81
-37
lines changed

debian/changelog

+11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
howdy (2.5.1) xenial; urgency=medium
2+
3+
* Removed dismiss_lockscreen as it could lock users out of their system (thanks @ujjwalbe, @ju916 and many others!)
4+
* Added option to disable howdy when the laptop lid is closed (thanks @accek!)
5+
* Added automatic fallback to default frame color palette (thanks @Ethiarpus!)
6+
* Added manual exposure setting (thanks @accek!)
7+
* Fixed test command ignoring dark frame threshold (thanks @eduncan911!)
8+
* Fixed import error in v4l2 recorder (thanks @timwelch!)
9+
10+
-- boltgolt <[email protected]> Fri, 29 Mar 2019 23:02:21 +0100
11+
112
howdy (2.5.0) xenial; urgency=medium
213

314
* Added FFmpeg and v4l2 recorders (thanks @timwelch!)

debian/postinst

+7-18
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,13 @@ if not os.path.exists("/tmp/howdy_picked_device"):
7070
if key == "timout":
7171
key = "timeout"
7272

73+
# MIGRATION 2.5.0 -> 2.5.1
74+
# Remove unsafe automatic dismissal of lock screen
75+
if key == "dismiss_lockscreen":
76+
if value == "true":
77+
print("DEPRECATION: Config falue dismiss_lockscreen is no longer supported because of login loop issues.")
78+
continue
79+
7380
try:
7481
newConf.set(section, key, value)
7582
# Add a new section where needed
@@ -152,24 +159,6 @@ log("Building dlib")
152159

153160
cmd = ["sudo", "python3", "setup.py", "install"]
154161
cuda_used = False
155-
flags = ""
156-
157-
# Get the CPU details
158-
with open("/proc/cpuinfo") as info:
159-
for line in info:
160-
if "flags" in line:
161-
flags = line
162-
break
163-
164-
# Use the most efficient instruction set the CPU supports
165-
if "avx" in flags:
166-
cmd += ["--yes", "USE_AVX_INSTRUCTIONS"]
167-
elif "sse4" in flags:
168-
cmd += ["--yes", "USE_SSE4_INSTRUCTIONS"]
169-
elif "sse3" in flags:
170-
cmd += ["--yes", "USE_SSE3_INSTRUCTIONS"]
171-
elif "sse2" in flags:
172-
cmd += ["--yes", "USE_SSE2_INSTRUCTIONS"]
173162

174163
# Compile and link dlib
175164
try:

debian/prerm

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ from shutil import rmtree
1212
if "remove" not in sys.argv and "purge" not in sys.argv:
1313
sys.exit(0)
1414

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

src/cli/test.py

+28-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Show a windows with the video stream and testing information
1+
# Show a window with the video stream and testing information
22

33
# Import required modules
44
import configparser
@@ -37,6 +37,10 @@
3737
if fh != -1:
3838
video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, fh)
3939

40+
# Read exposure and dark_thresholds from config to use in the main loop
41+
exposure = config.getint("video", "exposure", fallback=-1)
42+
dark_threshold = config.getfloat("video", "dark_threshold")
43+
4044
# Let the user know what's up
4145
print("""
4246
Opening a window with a test feed
@@ -106,7 +110,17 @@ def print_text(line_number, text):
106110

107111
# Grab a single frame of video
108112
ret, frame = video_capture.read()
109-
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
113+
114+
try:
115+
# Convert from color to grayscale
116+
# First processing of frame, so frame errors show up here
117+
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
118+
except RuntimeError:
119+
pass
120+
except cv2.error:
121+
print("\nUnknown camera, please check your 'device_path' config value.\n")
122+
raise
123+
110124
frame = clahe.apply(frame)
111125
# Make a frame to put overlays in
112126
overlay = frame.copy()
@@ -133,9 +147,6 @@ def print_text(line_number, text):
133147
# Draw the bar in green
134148
cv2.rectangle(overlay, p1, p2, (0, 200, 0), thickness=cv2.FILLED)
135149

136-
# Draw a stripe indicating the dark threshold
137-
cv2.rectangle(overlay, (8, 35), (20, 36), (255, 0, 0), thickness=cv2.FILLED)
138-
139150
# Print the statis in the bottom left
140151
print_text(0, "RESOLUTION: %dx%d" % (height, width))
141152
print_text(1, "FPS: %d" % (fps, ))
@@ -147,7 +158,7 @@ def print_text(line_number, text):
147158
cv2.putText(overlay, "SLOW MODE", (width - 66, height - 10), cv2.FONT_HERSHEY_SIMPLEX, .3, (0, 0, 255), 0, cv2.LINE_AA)
148159

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

157168
rec_tm = time.time()
158169
# Get the locations of all faces and their locations
159-
face_locations = face_detector(frame, 1) # upsample 1 time
170+
# Upsample it once
171+
face_locations = face_detector(frame, 1)
160172
rec_tm = time.time() - rec_tm
161173

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

208+
if exposure != -1:
209+
# For a strange reason on some cameras (e.g. Lenoxo X1E)
210+
# setting manual exposure works only after a couple frames
211+
# are captured and even after a delay it does not
212+
# always work. Setting exposure at every frame is
213+
# reliable though.
214+
video_capture.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 1 = Manual
215+
video_capture.set(cv2.CAP_PROP_EXPOSURE, float(exposure))
216+
196217
# On ctrl+C
197218
except KeyboardInterrupt:
198219
# Let the user know we're stopping

src/compare.py

+18
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ def stop(status):
144144
# This will let the camera adjust its light levels while we're importing for faster scanning
145145
video_capture.grab()
146146

147+
# Read exposure from config to use in the main loop
148+
exposure = config.getint("video", "exposure", fallback=-1)
149+
147150
# Note the time it took to open the camera
148151
timings["ic"] = time.time() - timings["ic"]
149152

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

186+
if frames == 1 and ret is False:
187+
print("Could not read from camera")
188+
exit(12)
189+
183190
try:
184191
# Convert from color to grayscale
185192
# First processing of frame, so frame errors show up here
186193
gsframe = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
194+
except RuntimeError:
195+
gsframe = frame
187196
except cv2.error:
188197
print("\nUnknown camera, please check your 'device_path' config value.\n")
189198
raise
@@ -261,3 +270,12 @@ def print_timing(label, k):
261270

262271
# End peacefully
263272
stop(0)
273+
274+
if exposure != -1:
275+
# For a strange reason on some cameras (e.g. Lenoxo X1E)
276+
# setting manual exposure works only after a couple frames
277+
# are captured and even after a delay it does not
278+
# always work. Setting exposure at every frame is
279+
# reliable though.
280+
video_capture.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 1 = Manual
281+
video_capture.set(cv2.CAP_PROP_EXPOSURE, float(exposure))

src/config.ini

+8-4
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,8 @@ suppress_unknown = false
1515
# Disable Howdy in remote shells
1616
ignore_ssh = true
1717

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

2321
# Disable howdy in the PAM
2422
# The howdy command will still function
@@ -70,6 +68,12 @@ device_format = v4l2
7068
# OPENCV only.
7169
force_mjpeg = false
7270

71+
# Specify exposure value explicitly. This disables autoexposure.
72+
# Use qv4l2 to determine an appropriate value.
73+
# OPENCV only.
74+
exposure = -1
75+
7376
[debug]
7477
# Show a short but detailed diagnostic report in console
78+
# Enabling this can cause some UI apps to fail, only enable it to debug
7579
end_report = false

src/pam.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import subprocess
55
import sys
66
import os
7+
import glob
78

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

29+
# Abort if lid is closed
30+
if config.getboolean("core", "ignore_closed_lid"):
31+
if any("closed" in open(f).read() for f in glob.glob("/proc/acpi/button/lid/*/state")):
32+
sys.exit(0)
33+
2834
# Alert the user that we are doing face detection
29-
if config.get("core", "detection_notice") == "true":
35+
if config.getboolean("core", "detection_notice"):
3036
pamh.conversation(pamh.Message(pamh.PAM_TEXT_INFO, "Attempting face detection"))
3137

3238
# Run compare as python3 subprocess to circumvent python version and import issues
@@ -50,11 +56,6 @@ def doAuth(pamh):
5056
if not config.getboolean("core", "no_confirmation"):
5157
pamh.conversation(pamh.Message(pamh.PAM_TEXT_INFO, "Identified face as " + pamh.get_user()))
5258

53-
# Try to dismiss the lock screen if enabled
54-
if config.get("core", "dismiss_lockscreen"):
55-
# Run it as root with a timeout of 1s, and never ask for a password through the UI
56-
subprocess.Popen(["sudo", "timeout", "1", "loginctl", "unlock-sessions", "--no-ask-password"])
57-
5859
return pamh.PAM_SUCCESS
5960

6061
# Otherwise, we can't discribe what happend but it wasn't successful

src/recorders/pyv4l2_reader.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from cv2 import cvtColor, COLOR_GRAY2BGR, CAP_PROP_FRAME_WIDTH, CAP_PROP_FRAME_HEIGHT
99

1010
try:
11-
from v4l2.frame import Frame
11+
from pyv4l2.frame import Frame
1212
except ImportError:
1313
print("Missing pyv4l2 module, please run:")
1414
print(" pip3 install pyv4l2\n")

0 commit comments

Comments
 (0)