diff --git a/src/cli/add.py b/src/cli/add.py index 112a07f..27b1364 100644 --- a/src/cli/add.py +++ b/src/cli/add.py @@ -105,14 +105,24 @@ time.sleep(2) # Will contain found face encodings enc = [] -# Count the amount or read frames +# Count the number of read frames frames = 0 +# Count the number of illuminated read frames +valid_frames = 0 +# Count the number of illuminated frames that +# were rejected for being too dark +dark_tries = 0 +# Track the running darkness total +dark_running_total = 0 +face_locations = None + 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: + frames += 1 # Grab a single frame of video frame, gsframe = video_capture.read_frame() gsframe = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) @@ -123,12 +133,23 @@ while frames < 60: # All values combined for percentage calculation hist_total = np.sum(hist) - # If the image is fully black or the frame exceeds threshold, + # 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 (hist[0] / hist_total * 100 > dark_threshold): + if (hist_total == 0) or (darkness == 100): continue - frames += 1 + # Include this frame in calculating our average session brightness + 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 # Get all faces from that frame as encodings face_locations = face_detector(gsframe, 1) @@ -137,12 +158,22 @@ while frames < 60: if face_locations: break -# 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") +video_capture.release() + +# If we've found no faces, try to determine why +if face_locations is None or not face_locations: + if valid_frames == 0: + print("Camera saw only black frames - is IR emitter working?") + elif valid_frames == dark_tries: + print("All frames were too dark, please check dark_threshold in config") + print("Average darkness: " + str(dark_running_total / valid_frames) + ", Threshold: " + str(dark_threshold)) + else: + print("No face detected, aborting") sys.exit(1) -elif not face_locations: - print("No face detected, aborting") + +# If more than 1 faces are detected we can't know wich one belongs to the user +elif len(face_locations) > 1: + print("Multiple faces detected, aborting") sys.exit(1) face_location = face_locations[0] diff --git a/src/compare.py b/src/compare.py index 5679877..bef7df5 100644 --- a/src/compare.py +++ b/src/compare.py @@ -60,6 +60,8 @@ user = sys.argv[1] 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 @@ -135,7 +137,9 @@ end_report = config.getboolean("debug", "end_report") # Start the read loop frames = 0 +valid_frames = 0 timings["fr"] = time.time() +dark_running_total = 0 clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) @@ -145,7 +149,12 @@ while True: # Stop if we've exceded the time limit if time.time() - timings["fr"] > timeout: - sys.exit(11) + if (dark_tries == valid_frames ): + print("All frames were too dark, please check dark_threshold in config") + print("Average darkness: " + str(dark_running_total / valid_frames) + ", Threshold: " + str(dark_threshold)) + sys.exit(13) + else: + sys.exit(11) # Grab a single frame of video frame, gsframe = video_capture.read_frame() @@ -157,9 +166,20 @@ while True: # All values combined for percentage calculation hist_total = np.sum(hist) - # If the image is fully black or the frame exceeds threshold, + # 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 (hist[0] / hist_total * 100 > dark_threshold): + 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 @@ -218,6 +238,7 @@ while True: # 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("Black frames ignored: %d " % (black_tries, )) print("Dark frames ignored: %d " % (dark_tries, )) print("Certainty of winning frame: %.3f" % (match * 10, )) diff --git a/src/pam.py b/src/pam.py index 3d44114..ea8ae16 100644 --- a/src/pam.py +++ b/src/pam.py @@ -50,6 +50,10 @@ def doAuth(pamh): # Status 12 means we aborted elif status == 12: return pamh.PAM_AUTH_ERR + # Status 13 means the image was too dark + elif status == 13: + pamh.conversation(pamh.Message(pamh.PAM_ERROR_MSG, "Face detection image too dark")) + return pamh.PAM_AUTH_ERR # Status 0 is a successful exit elif status == 0: # Show the success message if it isn't suppressed