From 140b4f3d6741778e8f9b774d0933af23c0915ebf Mon Sep 17 00:00:00 2001 From: Anthony Wharton Date: Sun, 12 May 2019 18:40:28 +0100 Subject: [PATCH 01/14] Add VideoCapture class --- src/recorders/video_capture.py | 116 +++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 src/recorders/video_capture.py diff --git a/src/recorders/video_capture.py b/src/recorders/video_capture.py new file mode 100644 index 0000000..d488ebe --- /dev/null +++ b/src/recorders/video_capture.py @@ -0,0 +1,116 @@ +# Top level class for a video capture providing simplified API's for common +# functions + +# Import required modules +import configparser +import cv2 +import os +import sys + +""" +Class to provide boilerplate code to build a video recorder with the +correct settings from the config file. + +The internal recorder can be accessed with 'video_capture.internal' +""" +class VideoCapture: + + """ + Creates a new VideoCapture instance depending on the settings in the + provided config file. + + Config can either be a string to the path, or a pre-setup configparser. + """ + def __init__(self, config): + if isinstance(config, str): + self.config = configparser.ConfigParser() + self.config.read(config) + else: + self.config = config + + # Check device path + if not os.path.exists(config.get("video", "device_path")): + print("Camera path is not configured correctly, " + + "please edit the 'device_path' config value.") + sys.exit(1) + + # Create reader + self.internal = None # The internal video recorder + self.fw = None # The frame width + self.fh = None # The frame height + self._create_reader() + + # Request a frame to wake the camera up + self.internal.grab() + + """ + Frees resources when destroyed + """ + def __del__(self): + if self is not None: + self.internal.release() + + """ + Reads a frame, returns the frame and an attempted grayscale conversion of + the frame in a tuple: + + (frame, grayscale_frame) + + If the grayscale conversion fails, both items in the tuple are identical. + """ + def read_frame(self): + # Grab a single frame of video + # Don't remove ret, it doesn't work without it + ret, frame = self.internal.read() + if not ret: + print("Failed to read camera specified in your 'device_path', " + + "aborting") + sys.exit(1) + + 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("\nAn error occurred in OpenCV\n") + raise + return frame, gsframe + + """ + Sets up the video reader instance + """ + def _create_reader(self): + if self.config.get("video", "recording_plugin") == "ffmpeg": + # Set the capture source for ffmpeg + from recorders.ffmpeg_reader import ffmpeg_reader + self.internal = ffmpeg_reader( + self.config.get("video", "device_path"), + self.config.get("video", "device_format") + ) + elif self.config.get("video", "recording_plugin") == "pyv4l2": + # Set the capture source for pyv4l2 + from recorders.pyv4l2_reader import pyv4l2_reader + self.internal = pyv4l2_reader( + self.config.get("video", "device_path"), + self.config.get("video", "device_format") + ) + else: + # Start video capture on the IR camera through OpenCV + self.internal = cv2.VideoCapture( + self.config.get("video", "device_path") + ) + + # Force MJPEG decoding if true + if self.config.getboolean("video", "force_mjpeg", fallback=False): + # Set a magic number, will enable MJPEG but is badly documentated + self.internal.set(cv2.CAP_PROP_FOURCC, 1196444237) + + # Set the frame width and height if requested + self.fw = self.config.getint("video", "frame_width", fallback=-1) + self.fh = self.config.getint("video", "frame_height", fallback=-1) + if self.fw != -1: + self.internal.set(cv2.CAP_PROP_FRAME_WIDTH, self.fw) + if self.fh != -1: + self.internal.set(cv2.CAP_PROP_FRAME_HEIGHT, self.fh) From 1555ffe82fbee074090b8ccc6a417f6647a0958e Mon Sep 17 00:00:00 2001 From: Anthony Wharton Date: Sun, 12 May 2019 18:57:26 +0100 Subject: [PATCH 02/14] Refactor compare.py to use VideoCapture --- src/compare.py | 67 +++++++------------------------------------------- 1 file changed, 9 insertions(+), 58 deletions(-) diff --git a/src/compare.py b/src/compare.py index 98c6b72..17e1524 100644 --- a/src/compare.py +++ b/src/compare.py @@ -18,6 +18,7 @@ import cv2 import dlib import numpy as np import _thread as thread +from recorders.video_capture import VideoCapture def init_detector(lock): @@ -46,13 +47,6 @@ def init_detector(lock): timings["ll"] = time.time() - timings["ll"] lock.release() - -def stop(status): - """Stop the execution and close video stream""" - video_capture.release() - sys.exit(status) - - # Make sure we were given an username to tast against if len(sys.argv) < 2: sys.exit(12) @@ -113,36 +107,7 @@ thread.start_new_thread(init_detector, (lock, )) # Start video capture on the IR camera timings["ic"] = time.time() -# Check if the user explicitly set ffmpeg as recorder -if config.get("video", "recording_plugin") == "ffmpeg": - # Set the capture source for ffmpeg - from recorders.ffmpeg_reader import ffmpeg_reader - video_capture = ffmpeg_reader(config.get("video", "device_path"), config.get("video", "device_format")) -elif config.get("video", "recording_plugin") == "pyv4l2": - # Set the capture source for pyv4l2 - from recorders.pyv4l2_reader import pyv4l2_reader - video_capture = pyv4l2_reader(config.get("video", "device_path"), config.get("video", "device_format")) -else: - # Start video capture on the IR camera through OpenCV - video_capture = cv2.VideoCapture(config.get("video", "device_path")) - -# Force MJPEG decoding if true -if config.getboolean("video", "force_mjpeg", fallback=False): - # Set a magic number, will enable MJPEG but is badly documented - # 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) -fh = config.getint("video", "frame_height", fallback=-1) -if fw != -1: - video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, fw) -if fh != -1: - video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, fh) - -# Capture a single frame so the camera becomes active -# This will let the camera adjust its light levels while we're importing for faster scanning -video_capture.grab() +video_capture = VideoCapture(config) # Read exposure from config to use in the main loop exposure = config.getint("video", "exposure", fallback=-1) @@ -158,7 +123,7 @@ 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.get(cv2.CAP_PROP_FRAME_HEIGHT) or 1 +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 @@ -178,24 +143,10 @@ while True: # Stop if we've exceded the time limit if time.time() - timings["fr"] > timeout: - stop(11) + sys.exit(11) # 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 + frame, gsframe = video_capture.read_frame() # Create a histogram of the image with 8 values hist = cv2.calcHist([gsframe], [0], None, [8], [0, 256]) @@ -255,7 +206,7 @@ while True: print_timing("Total time", "tt") print("\nResolution") - width = video_capture.get(cv2.CAP_PROP_FRAME_WIDTH) or 1 + 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] @@ -269,7 +220,7 @@ while True: print("Winning model: %d (\"%s\")" % (match_index, models[match_index]["label"])) # End peacefully - stop(0) + sys.exit(0) if exposure != -1: # For a strange reason on some cameras (e.g. Lenoxo X1E) @@ -277,5 +228,5 @@ while True: # 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)) + video_capture.intenal.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 1 = Manual + video_capture.intenal.set(cv2.CAP_PROP_EXPOSURE, float(exposure)) From 804016d1a07739dc651575d6bb7c8195db4194e4 Mon Sep 17 00:00:00 2001 From: Anthony Wharton Date: Sun, 12 May 2019 18:40:59 +0100 Subject: [PATCH 03/14] Refactor add.py to use VideoCapture --- src/cli/add.py | 44 ++++---------------------------------------- 1 file changed, 4 insertions(+), 40 deletions(-) diff --git a/src/cli/add.py b/src/cli/add.py index 3106055..a345037 100644 --- a/src/cli/add.py +++ b/src/cli/add.py @@ -9,6 +9,7 @@ import configparser import builtins import cv2 import numpy as np +from recorders.video_capture import VideoCapture # Try to import dlib and give a nice error if we can't # Add should be the first point where import issues show up @@ -35,10 +36,6 @@ if not os.path.isfile(path + "/../dlib-data/shape_predictor_5_face_landmarks.dat config = configparser.ConfigParser() config.read(path + "/../config.ini") -if not os.path.exists(config.get("video", "device_path")): - print("Camera path is not configured correctly, please edit the 'device_path' config value.") - sys.exit(1) - use_cnn = config.getboolean("core", "use_cnn", fallback=False) if use_cnn: face_detector = dlib.cnn_face_detection_model_v1(path + "/../dlib-data/mmod_human_face_detector.dat") @@ -98,36 +95,8 @@ insert_model = { "data": [] } -# Check if the user explicitly set ffmpeg as recorder -if config.get("video", "recording_plugin") == "ffmpeg": - # Set the capture source for ffmpeg - from recorders.ffmpeg_reader import ffmpeg_reader - video_capture = ffmpeg_reader(config.get("video", "device_path"), config.get("video", "device_format")) -elif config.get("video", "recording_plugin") == "pyv4l2": - # Set the capture source for pyv4l2 - from recorders.pyv4l2_reader import pyv4l2_reader - video_capture = pyv4l2_reader(config.get("video", "device_path"), config.get("video", "device_format")) -else: - # Start video capture on the IR camera through OpenCV - video_capture = cv2.VideoCapture(config.get("video", "device_path")) - -# Force MJPEG decoding if true -if config.getboolean("video", "force_mjpeg", fallback=False): - # Set a magic number, will enable MJPEG but is badly documentated - video_capture.set(cv2.CAP_PROP_FOURCC, 1196444237) - -# Set the frame width and height if requested -fw = config.getint("video", "frame_width", fallback=-1) -fh = config.getint("video", "frame_height", fallback=-1) -if fw != -1: - video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, fw) - -if fh != -1: - video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, fh) - -# Request a frame to wake the camera up -video_capture.grab() - +# Set up video_capture +video_capture = VideoCapture(config) print("\nPlease look straight into the camera") # Give the user time to read @@ -141,10 +110,7 @@ dark_threshold = config.getfloat("video", "dark_threshold") # Loop through frames till we hit a timeout while frames < 60: - # Grab a single frame of video - # Don't remove ret, it doesn't work without it - ret, frame = video_capture.read() - gsframe = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + frame, gsframe = video_capture.read_frame() # Create a histogram of the image with 8 values hist = cv2.calcHist([gsframe], [0], None, [8], [0, 256]) @@ -165,8 +131,6 @@ while frames < 60: if face_locations: break -video_capture.release() - # If more than 1 faces are detected we can't know wich one belongs to the user if len(face_locations) > 1: print("Multiple faces detected, aborting") From 200e536b5eacb72f9fe4a7409958f803540e29b7 Mon Sep 17 00:00:00 2001 From: Anthony Wharton Date: Sun, 12 May 2019 18:48:50 +0100 Subject: [PATCH 04/14] Refactor test.py to use VideoCapture --- src/cli/test.py | 35 +++++------------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/src/cli/test.py b/src/cli/test.py index 16fadb1..de92ce3 100644 --- a/src/cli/test.py +++ b/src/cli/test.py @@ -7,6 +7,7 @@ import sys import time import cv2 import dlib +from recorders.video_capture import VideoCapture # Get the absolute path to the current file path = os.path.dirname(os.path.abspath(__file__)) @@ -20,22 +21,7 @@ if config.get("video", "recording_plugin") != "opencv": print("Aborting") sys.exit(12) -# Start capturing from the configured webcam -video_capture = cv2.VideoCapture(config.get("video", "device_path")) - -# 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) - -# Set the frame width and height if requested -fw = config.getint("video", "frame_width", fallback=-1) -fh = config.getint("video", "frame_height", fallback=-1) -if fw != -1: - video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, fw) - -if fh != -1: - video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, fh) +video_capture = VideoCapture(config) # Read exposure and dark_thresholds from config to use in the main loop exposure = config.getint("video", "exposure", fallback=-1) @@ -109,17 +95,7 @@ try: sec_frames = 0 # Grab a single frame of video - ret, frame = video_capture.read() - - 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 = video_capture.read_frame() frame = clahe.apply(frame) # Make a frame to put overlays in @@ -211,8 +187,8 @@ try: # 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)) + video_capture.intenal.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 1 = Manual + video_capture.intenal.set(cv2.CAP_PROP_EXPOSURE, float(exposure)) # On ctrl+C except KeyboardInterrupt: @@ -220,5 +196,4 @@ except KeyboardInterrupt: print("\nClosing window") # Release handle to the webcam - video_capture.release() cv2.destroyAllWindows() From 4d614ca44370eccb8dbddfbe4fbdd46828615d3d Mon Sep 17 00:00:00 2001 From: Karl-Philipp Richter Date: Tue, 14 May 2019 15:47:02 +0200 Subject: [PATCH 05/14] Expanded Python versions in .travis.yml --- .travis.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6f7d486..847bbae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,11 @@ sudo: required +dist: xenial language: python -python: "3.6" +python: + - "3.4" + - "3.6" + - "3.7" + - "3.8-dev" script: # Build the binary (.deb) From 67bc656801411eeced33e1bced8f44a1c30fcd0c Mon Sep 17 00:00:00 2001 From: Alan Rager Date: Sat, 29 Jun 2019 07:21:26 -0700 Subject: [PATCH 06/14] use ffmpeg instead of streamer for checking camera --- debian/control | 2 +- debian/preinst | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/debian/control b/debian/control index 2b4262b..9f65b8d 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,7 @@ Vcs-Git: https://github.com/boltgolt/howdy Package: howdy Homepage: https://github.com/boltgolt/howdy Architecture: all -Depends: ${misc:Depends}, curl|wget, python3, python3-pip, python3-dev, python3-setuptools, libpam-python, fswebcam, libopencv-dev, cmake, streamer +Depends: ${misc:Depends}, curl|wget, python3, python3-pip, python3-dev, python3-setuptools, libpam-python, fswebcam, libopencv-dev, cmake, ffmpeg Recommends: libatlas-base-dev | libopenblas-dev | liblapack-dev Suggests: nvidia-cuda-dev (>= 7.5) Description: Howdy: Windows Hello style authentication for Linux. diff --git a/debian/preinst b/debian/preinst index e355a15..3a5ce2c 100755 --- a/debian/preinst +++ b/debian/preinst @@ -73,7 +73,12 @@ for dev in devices: print("Trying " + device_name) # Let fswebcam keep the camera open in the background - sub = subprocess.Popen(["streamer -t 1:0:0 -c /dev/v4l/by-path/" + dev + " -b 16 -f rgb24 -o /dev/null 1>/dev/null 2>/dev/null"], shell=True, preexec_fn=os.setsid) + sub = subprocess.Popen( + "ffmpeg -f v4l2 -framerate 25 -video_size 640_480 -i /dev/v4l/by-path/%s -f null -loglevel -8 /dev/null" % dev, + shell=True, + preexec_fn=os.setsid, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE) try: # Ask the user if this is the right one From 0eb26c044d54bd289c1bc4efdbfe0722f9ce0bfa Mon Sep 17 00:00:00 2001 From: Alan Rager Date: Sat, 6 Jul 2019 13:02:59 -0700 Subject: [PATCH 07/14] use fswebcam instead --- debian/control | 2 +- debian/preinst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/control b/debian/control index 9f65b8d..efb16a1 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,7 @@ Vcs-Git: https://github.com/boltgolt/howdy Package: howdy Homepage: https://github.com/boltgolt/howdy Architecture: all -Depends: ${misc:Depends}, curl|wget, python3, python3-pip, python3-dev, python3-setuptools, libpam-python, fswebcam, libopencv-dev, cmake, ffmpeg +Depends: ${misc:Depends}, curl|wget, python3, python3-pip, python3-dev, python3-setuptools, libpam-python, fswebcam, libopencv-dev, cmake, fswebcam Recommends: libatlas-base-dev | libopenblas-dev | liblapack-dev Suggests: nvidia-cuda-dev (>= 7.5) Description: Howdy: Windows Hello style authentication for Linux. diff --git a/debian/preinst b/debian/preinst index 3a5ce2c..8430d4a 100755 --- a/debian/preinst +++ b/debian/preinst @@ -74,7 +74,7 @@ for dev in devices: # Let fswebcam keep the camera open in the background sub = subprocess.Popen( - "ffmpeg -f v4l2 -framerate 25 -video_size 640_480 -i /dev/v4l/by-path/%s -f null -loglevel -8 /dev/null" % dev, + "fswebcam -l 1 -d /dev/v4l/by-path/%s" % dev, shell=True, preexec_fn=os.setsid, stdout=subprocess.PIPE, From 983ab0a9d0e408046601b644d83b09ee02875d17 Mon Sep 17 00:00:00 2001 From: ajayTDM <35770004+Ajayneethikannan@users.noreply.github.com> Date: Sat, 28 Sep 2019 15:28:30 +0530 Subject: [PATCH 08/14] Fix small typo in compare.py --- src/compare.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compare.py b/src/compare.py index 98c6b72..6f71606 100644 --- a/src/compare.py +++ b/src/compare.py @@ -94,7 +94,7 @@ config.read(PATH + "/config.ini") # Get all config values needed use_cnn = config.getboolean("core", "use_cnn", fallback=False) -timeout = config.getint("video", "timout", fallback=5) +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) From de8aaf5aeeb3eee622409439c0b3a2dbe963ba6b Mon Sep 17 00:00:00 2001 From: Rushabh Vasani <46084304+RushabhVasani@users.noreply.github.com> Date: Fri, 18 Oct 2019 16:54:39 +0530 Subject: [PATCH 09/14] Update postinst --- debian/postinst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/postinst b/debian/postinst index 7ab3b89..4ede83c 100755 --- a/debian/postinst +++ b/debian/postinst @@ -109,6 +109,12 @@ log("Upgrading pip to the latest version") # Update pip handleStatus(sc(["pip3", "install", "--upgrade", "pip"])) + +log("Upgrading numpy to the lateset version") + +# Update numpy +handleStatus(subprocess.call(["pip3", "install", "--upgrade", "numpy"])) + log("Downloading and unpacking data files") # Run the bash script to download and unpack the .dat files needed From 0444ca933fbb08ebfb892b313972b42064193519 Mon Sep 17 00:00:00 2001 From: Peter-Simon Dieterich Date: Fri, 1 Nov 2019 11:49:19 +0100 Subject: [PATCH 10/14] Fix missing colors in overlay --- src/cli/test.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cli/test.py b/src/cli/test.py index 16fadb1..02a557c 100644 --- a/src/cli/test.py +++ b/src/cli/test.py @@ -124,6 +124,7 @@ try: frame = clahe.apply(frame) # Make a frame to put overlays in overlay = frame.copy() + overlay = cv2.cvtColor(overlay, cv2.COLOR_GRAY2BGR) # Fetch the frame height and width height, width = frame.shape[:2] @@ -190,6 +191,7 @@ try: # Add the overlay to the frame with some transparency alpha = 0.65 + frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR) cv2.addWeighted(overlay, alpha, frame, 1 - alpha, 0, frame) # Show the image in a window From 799628eddf64a5264b7d76ac2eb263990dbd3f59 Mon Sep 17 00:00:00 2001 From: Peter-Simon Dieterich Date: Fri, 1 Nov 2019 11:53:17 +0100 Subject: [PATCH 11/14] Apply CLAHE to frames in add.py and compare.py --- src/cli/add.py | 3 +++ src/compare.py | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/cli/add.py b/src/cli/add.py index 3106055..44b4480 100644 --- a/src/cli/add.py +++ b/src/cli/add.py @@ -139,12 +139,15 @@ enc = [] frames = 0 dark_threshold = config.getfloat("video", "dark_threshold") +clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) + # Loop through frames till we hit a timeout while frames < 60: # Grab a single frame of video # Don't remove ret, it doesn't work without it ret, frame = video_capture.read() gsframe = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + gsframe = clahe.apply(gsframe) # Create a histogram of the image with 8 values hist = cv2.calcHist([gsframe], [0], None, [8], [0, 256]) diff --git a/src/compare.py b/src/compare.py index 98c6b72..228f227 100644 --- a/src/compare.py +++ b/src/compare.py @@ -172,6 +172,8 @@ end_report = config.getboolean("debug", "end_report") frames = 0 timings["fr"] = time.time() +clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) + while True: # Increment the frame count every loop frames += 1 @@ -197,6 +199,8 @@ while True: print("\nUnknown camera, please check your 'device_path' config value.\n") raise + gsframe = clahe.apply(gsframe) + # Create a histogram of the image with 8 values hist = cv2.calcHist([gsframe], [0], None, [8], [0, 256]) # All values combined for percentage calculation From b7f2b665925a90b7bcb55fa54e2b12069f981019 Mon Sep 17 00:00:00 2001 From: Musikid Date: Sun, 1 Mar 2020 10:37:13 +0100 Subject: [PATCH 12/14] Fix the fedora .spec file --- fedora/howdy.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fedora/howdy.spec b/fedora/howdy.spec index bfd7f63..2541943 100644 --- a/fedora/howdy.spec +++ b/fedora/howdy.spec @@ -32,7 +32,7 @@ Requires: python3dist(v4l2) Requires: python3-face_recognition Supplements: python3-face_recognition_models Requires: python3-opencv -Requires: python3-pam +Requires: pam_python %endif From e7b5262683e3425bc8850bcc180842d16d735394 Mon Sep 17 00:00:00 2001 From: Arthur Bols Date: Sun, 3 May 2020 16:16:27 +0200 Subject: [PATCH 13/14] Fix fedora dependencies --- fedora/howdy.spec | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/fedora/howdy.spec b/fedora/howdy.spec index 2541943..c558f35 100644 --- a/fedora/howdy.spec +++ b/fedora/howdy.spec @@ -9,7 +9,7 @@ Version: 2.5.1 %if %{with_snapshot} Release: 0.1.git.%{date}%{shortcommit}%{?dist} %else -Release: 3%{?dist} +Release: 4%{?dist} %endif Summary: Windows Helloâ„¢ style authentication for Linux @@ -27,10 +27,7 @@ BuildRequires: polkit-devel %if 0%{?fedora} # We need python3-devel for pathfix.py BuildRequires: python3-devel -Requires: python3dist(dlib) >= 6.0 -Requires: python3dist(v4l2) -Requires: python3-face_recognition -Supplements: python3-face_recognition_models +Requires: python3dist(dlib) >= 6.0 Requires: python3-opencv Requires: pam_python %endif From f826d91a30c2f199e1c1408f8f715fe07eaacf2a Mon Sep 17 00:00:00 2001 From: Ryan Butler Date: Sat, 20 Jun 2020 12:34:51 -0400 Subject: [PATCH 14/14] Inaccurate cli message fixed --- src/cli/list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/list.py b/src/cli/list.py index 08a1e9f..2cc9b9c 100644 --- a/src/cli/list.py +++ b/src/cli/list.py @@ -14,7 +14,7 @@ user = builtins.howdy_user # Check if the models file has been created yet if not os.path.exists(path + "/models"): print("Face models have not been initialized yet, please run:") - print("\n\thowdy " + user + " add\n") + print("\n\tsudo howdy -U " + user + " add\n") sys.exit(1) # Path to the models file