Fix facial recognition

Scaling still seems to be imperfect
This commit is contained in:
slashtechno 2023-10-14 17:37:42 -05:00
parent b6948aded2
commit b2f10280b3
Signed by: slashtechno
GPG Key ID: 8EC1D9D9286C2B17
4 changed files with 92 additions and 40 deletions

2
.vscode/launch.json vendored
View File

@ -8,7 +8,7 @@
"name": "Python: Module",
"type": "python",
"request": "launch",
"module": "set-detect-notify",
"module": "set_detect_notify",
"justMyCode": true
}
]

View File

@ -46,7 +46,8 @@ def main():
# Set it to the env RUN_SCALE if it isn't blank, otherwise set it to 0.25
default=os.environ["RUN_SCALE"]
if "RUN_SCALE" in os.environ and os.environ["RUN_SCALE"] != ""
else 0.25, # noqa: E501
# else 0.25,
else 1,
type=float,
help="The scale to run the detection at, default is 0.25",
)
@ -55,7 +56,8 @@ def main():
# Set it to the env VIEW_SCALE if it isn't blank, otherwise set it to 0.75
default=os.environ["VIEW_SCALE"]
if "VIEW_SCALE" in os.environ and os.environ["VIEW_SCALE"] != ""
else 0.75, # noqa: E501
# else 0.75,
else 1,
type=float,
help="The scale to view the detection at, default is 0.75",
)
@ -191,6 +193,26 @@ def main():
for i, r in enumerate(results):
# list of dicts with each dict containing a label, x1, y1, x2, y2
plot_boxes = []
# The following is stuff for people
# This is still in the for loop as each result, no matter if anything is detected, will be present.
# Thus, there will always be one result (r)
if face_details := utils.recognize_face(path_to_directory=Path(args.faces_directory), run_frame=run_frame):
plot_boxes.append( face_details )
objects_and_peoples=notify.thing_detected(
thing_name=face_details["label"],
objects_and_peoples=objects_and_peoples,
detection_type="peoples",
detection_window=args.detection_window,
detection_duration=args.detection_duration,
notification_window=args.notification_window,
ntfy_url=args.ntfy_url,
)
# The following is stuff for objects
# Setup dictionary of object names
if objects_and_peoples["objects"] == {} or objects_and_peoples["objects"] is None:
for name in r.names.values():

View File

@ -44,42 +44,51 @@ def thing_detected(
respective_type = objects_and_peoples[detection_type]
# (re)start cycle
if (
# If the object has not been detected before
respective_type[thing_name]["last_detection_time"] is None
# If the last detection was more than 15 seconds ago
or time.time() - respective_type[thing_name]["last_detection_time"]
> detection_window
):
# Set the last detection time to now
respective_type[thing_name]["last_detection_time"] = time.time()
print(f"First detection of {thing_name} in this detection window")
# This line is important. It resets the detection duration when the object hasn't been detected for a while
# If detection duration is None, don't print anything.
# Otherwise, print that the detection duration is being reset due to inactivity
if respective_type[thing_name]["detection_duration"] is not None:
print(
f"Resetting detection duration for {thing_name} since it hasn't been detected for {detection_window} seconds" # noqa: E501
)
respective_type[thing_name]["detection_duration"] = 0
else:
# Check if the last notification was less than 15 seconds ago
# If it was, then don't do anything
try:
if (
time.time() - respective_type[thing_name]["last_detection_time"]
<= notification_window
# If the object has not been detected before
respective_type[thing_name]["last_detection_time"] is None
# If the last detection was more than 15 seconds ago
or time.time() - respective_type[thing_name]["last_detection_time"]
> detection_window
):
pass
# If it was more than 15 seconds ago, reset the detection duration
# This effectively resets the notification timer
else:
print("Notification timer has expired - resetting")
# Set the last detection time to now
respective_type[thing_name]["last_detection_time"] = time.time()
print(f"First detection of {thing_name} in this detection window")
# This line is important. It resets the detection duration when the object hasn't been detected for a while
# If detection duration is None, don't print anything.
# Otherwise, print that the detection duration is being reset due to inactivity
if respective_type[thing_name]["detection_duration"] is not None:
print(
f"Resetting detection duration for {thing_name} since it hasn't been detected for {detection_window} seconds" # noqa: E501
)
respective_type[thing_name]["detection_duration"] = 0
respective_type[thing_name]["detection_duration"] += (
time.time() - respective_type[thing_name]["last_detection_time"]
)
# print("Updating detection duration")
respective_type[thing_name]["last_detection_time"] = time.time()
else:
# Check if the last NOTIFICATION was less than 15 seconds ago
# If it was, then don't do anything
if (
time.time() - respective_type[thing_name]["last_detection_time"]
<= notification_window
):
pass
# If it was more than 15 seconds ago, reset the detection duration
# This effectively resets the notification timer
else:
print("Notification timer has expired - resetting")
respective_type[thing_name]["detection_duration"] = 0
respective_type[thing_name]["detection_duration"] += (
time.time() - respective_type[thing_name]["last_detection_time"]
)
# print("Updating detection duration")
respective_type[thing_name]["last_detection_time"] = time.time()
except KeyError:
# If the object has not been detected before
respective_type[thing_name] = {
"last_detection_time": time.time(),
"detection_duration": 0,
"last_notification_time": None,
}
print(f"First detection of {thing_name} ever")
# (re)send notification
# Check if detection has been ongoing for 2 seconds or more in the past 15 seconds

View File

@ -3,6 +3,8 @@ import numpy as np
from pathlib import Path
from deepface import DeepFace
first_face_try = True
def plot_label(
# list of dicts with each dict containing a label, x1, y1, x2, y2
boxes: list = None,
@ -67,7 +69,7 @@ def recognize_face(
Accepts a path to a directory of images of faces to be used as a refference
In addition, accepts an opencv image to be used as the frame to be searched
Returns a list of dictionaries, containing a single dictonary as currently only 1 face can be detected in each frame
Returns a single dictonary as currently only 1 face can be detected in each frame
dict contains the following keys: label, x1, y1, x2, y2
The directory should be structured as follows:
faces/
@ -84,8 +86,23 @@ def recognize_face(
Point is, `name` is the name of the person in the images in the directory `name`
That name will be used as the label for the face in the frame
'''
global first_face_try
# If it's the first time the function is being run, remove representations_vgg_face.pkl, if it exists
if first_face_try:
try:
Path("representations_vgg_face.pkl").unlink()
print("Removing representations_vgg_face.pkl")
except FileNotFoundError:
pass
first_face_try = False
# face_dataframes is a vanilla list of dataframes
face_dataframes = DeepFace.find(run_frame, db_path=str(path_to_directory))
try:
face_dataframes = DeepFace.find(run_frame, db_path=str(path_to_directory), enforce_detection=True, silent=True)
except ValueError as e:
if str(e) == "Face could not be detected. Please confirm that the picture is a face photo or consider to set enforce_detection param to False.":
return None
# Iteate over the dataframes
for df in face_dataframes:
# The last row is the highest confidence
@ -103,8 +120,12 @@ def recognize_face(
"x2": df.iloc[-1]["source_x"] + df.iloc[-1]["source_w"],
"y2": df.iloc[-1]["source_y"] + df.iloc[-1]["source_h"],
}
return [dict(label=label, **coordinates)]
distance = df.iloc[-1]["VGG-Face_cosine"]
# if 0.5 < distance < 0.7:
# label = "Unknown"
to_return = dict(label=label, **coordinates)
print(f'Confindence: {distance}, filname: {path_to_image.name}, to_return: {to_return}')
return to_return
'''
Example dataframe, for reference