Fix facial recognition
Scaling still seems to be imperfect
This commit is contained in:
parent
b6948aded2
commit
b2f10280b3
|
@ -8,7 +8,7 @@
|
|||
"name": "Python: Module",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "set-detect-notify",
|
||||
"module": "set_detect_notify",
|
||||
"justMyCode": true
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue