201 lines
5.9 KiB
Python
201 lines
5.9 KiB
Python
# Show a window with the video stream and testing information
|
|
|
|
# Import required modules
|
|
import configparser
|
|
import os
|
|
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__))
|
|
|
|
# Read config from disk
|
|
config = configparser.ConfigParser()
|
|
config.read(path + "/../config.ini")
|
|
|
|
if config.get("video", "recording_plugin") != "opencv":
|
|
print("Howdy has been configured to use a recorder which doesn't support the test command yet")
|
|
print("Aborting")
|
|
sys.exit(12)
|
|
|
|
video_capture = VideoCapture(config)
|
|
|
|
# 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
|
|
|
|
Press ctrl+C in this terminal to quit
|
|
Click on the image to enable or disable slow mode
|
|
""")
|
|
|
|
|
|
def mouse(event, x, y, flags, param):
|
|
"""Handle mouse events"""
|
|
global slow_mode
|
|
|
|
# Toggle slowmode on click
|
|
if event == cv2.EVENT_LBUTTONDOWN:
|
|
slow_mode = not slow_mode
|
|
|
|
|
|
def print_text(line_number, text):
|
|
"""Print the status text by line number"""
|
|
cv2.putText(overlay, text, (10, height - 10 - (10 * line_number)), cv2.FONT_HERSHEY_SIMPLEX, .3, (0, 255, 0), 0, cv2.LINE_AA)
|
|
|
|
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'
|
|
)
|
|
else:
|
|
face_detector = dlib.get_frontal_face_detector()
|
|
|
|
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
|
|
|
|
# Open the window and attach a a mouse listener
|
|
cv2.namedWindow("Howdy Test")
|
|
cv2.setMouseCallback("Howdy Test", mouse)
|
|
|
|
# Enable a delay in the loop
|
|
slow_mode = False
|
|
# Count all frames ever
|
|
total_frames = 0
|
|
# Count all frames per second
|
|
sec_frames = 0
|
|
# Last secands FPS
|
|
fps = 0
|
|
# The current second we're counting
|
|
sec = int(time.time())
|
|
# recognition time
|
|
rec_tm = 0
|
|
|
|
# Wrap everything in an keyboard interupt handler
|
|
try:
|
|
while True:
|
|
frame_tm = time.time()
|
|
|
|
# Increment the frames
|
|
total_frames += 1
|
|
sec_frames += 1
|
|
|
|
# Id we've entered a new second
|
|
if sec != int(frame_tm):
|
|
# Set the last seconds FPS
|
|
fps = sec_frames
|
|
|
|
# Set the new second and reset the counter
|
|
sec = int(frame_tm)
|
|
sec_frames = 0
|
|
|
|
# Grab a single frame of video
|
|
_, frame = video_capture.read_frame()
|
|
|
|
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]
|
|
|
|
# Create a histogram of the image with 8 values
|
|
hist = cv2.calcHist([frame], [0], None, [8], [0, 256])
|
|
# All values combined for percentage calculation
|
|
hist_total = int(sum(hist)[0])
|
|
# Fill with the overal containing percentage
|
|
hist_perc = []
|
|
|
|
# Loop though all values to calculate a percentage and add it to the overlay
|
|
for index, value in enumerate(hist):
|
|
value_perc = float(value[0]) / hist_total * 100
|
|
hist_perc.append(value_perc)
|
|
|
|
# Top left pont, 10px margins
|
|
p1 = (20 + (10 * index), 10)
|
|
# Bottom right point makes the bar 10px thick, with an height of half the percentage
|
|
p2 = (10 + (10 * index), int(value_perc / 2 + 10))
|
|
# Draw the bar in green
|
|
cv2.rectangle(overlay, p1, p2, (0, 200, 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, ))
|
|
print_text(2, "FRAMES: %d" % (total_frames, ))
|
|
print_text(3, "RECOGNITION: %dms" % (round(rec_tm * 1000), ))
|
|
|
|
# Show that slow mode is on, if it's on
|
|
if slow_mode:
|
|
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] > 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:
|
|
# SHow that this is an active frame
|
|
cv2.putText(overlay, "SCAN FRAME", (width - 68, 16), cv2.FONT_HERSHEY_SIMPLEX, .3, (0, 255, 0), 0, cv2.LINE_AA)
|
|
|
|
rec_tm = time.time()
|
|
# Get the locations of all faces and their locations
|
|
# 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
|
|
for loc in face_locations:
|
|
if use_cnn:
|
|
loc = loc.rect
|
|
|
|
# Get the center X and Y from the rectangular points
|
|
x = int((loc.right() - loc.left()) / 2) + loc.left()
|
|
y = int((loc.bottom() - loc.top()) / 2) + loc.top()
|
|
|
|
# Get the raduis from the with of the square
|
|
r = (loc.right() - loc.left()) / 2
|
|
# Add 20% padding
|
|
r = int(r + (r * 0.2))
|
|
|
|
# Draw the Circle in green
|
|
cv2.circle(overlay, (x, y), r, (0, 0, 230), 2)
|
|
|
|
# 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
|
|
cv2.imshow("Howdy Test", frame)
|
|
|
|
# Quit on any keypress
|
|
if cv2.waitKey(1) != -1:
|
|
raise KeyboardInterrupt()
|
|
|
|
frame_time = time.time() - frame_tm
|
|
|
|
# Delay the frame if slowmode is on
|
|
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.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:
|
|
# Let the user know we're stopping
|
|
print("\nClosing window")
|
|
|
|
# Release handle to the webcam
|
|
cv2.destroyAllWindows()
|