Fixed scaling 🎉

This commit is contained in:
slashtechno 2023-10-14 19:25:27 -05:00
parent 7d942ee456
commit 1d17bb629b
Signed by: slashtechno
GPG Key ID: 8EC1D9D9286C2B17
3 changed files with 71 additions and 59 deletions

View File

@ -197,7 +197,9 @@ def main():
# 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):
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"],
@ -209,12 +211,12 @@ def main():
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:
if (
objects_and_peoples["objects"] == {}
or objects_and_peoples["objects"] is None
):
for name in r.names.values():
objects_and_peoples["objects"][name] = {
"last_detection_time": None,
@ -274,8 +276,7 @@ def main():
ntfy_url=args.ntfy_url,
)
# TODO: On 10-14-2023, while testing, it seemed the bounding box was too low. Troubleshoot if it's a plotting problem.
# To do so, use r.plot() to cross reference the bounding box drawn by the plot_label function and r.plot()
# To debug plotting, use r.plot() to cross reference the bounding boxes drawn by the plot_label() and r.plot()
frame_to_show = utils.plot_label(
boxes=plot_boxes,
full_frame=frame,
@ -297,5 +298,6 @@ def main():
video_capture.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()

View File

@ -2,10 +2,9 @@ import httpx
import time
'''
"""
Structure of objects_and_peoples
Really, the only reason peoples is a separate dictionary is to prevent duplicates, though it just makes the code more complicated.
TODO: Make a function to check if a person is in the objects dictionary and vice versa
{
"objects": {
"object_name": {
@ -22,7 +21,7 @@ TODO: Make a function to check if a person is in the objects dictionary and vice
},
},
}
'''
"""
# objects_and_peoples = {}
@ -33,12 +32,12 @@ def thing_detected(
detection_window: int = 15,
detection_duration: int = 2,
notification_window: int = 15,
ntfy_url: str = "https://ntfy.sh/set-detect-notify"
ntfy_url: str = "https://ntfy.sh/set-detect-notify",
) -> dict:
'''
"""
A function to make sure 2 seconds of detection is detected in 15 seconds, 15 seconds apart.
Takes a dict that will be retured with the updated detection times. MAKE SURE TO SAVE THE RETURNED DICTIONARY
'''
"""
# "Alias" the objects and peoples dictionaries so it's easier to work with
respective_type = objects_and_peoples[detection_type]
@ -93,22 +92,18 @@ def thing_detected(
# (re)send notification
# Check if detection has been ongoing for 2 seconds or more in the past 15 seconds
if (
respective_type[thing_name]["detection_duration"]
>= detection_duration
respective_type[thing_name]["detection_duration"] >= detection_duration
and time.time() - respective_type[thing_name]["last_detection_time"]
<= detection_window
):
# If the last notification was more than 15 seconds ago, then send a notification
if (
respective_type[thing_name]["last_notification_time"] is None
or time.time()
- respective_type[thing_name]["last_notification_time"]
or time.time() - respective_type[thing_name]["last_notification_time"]
> notification_window
):
respective_type[thing_name]["last_notification_time"] = time.time()
print(
f"Detected {thing_name} for {detection_duration} seconds"
)
print(f"Detected {thing_name} for {detection_duration} seconds")
headers = construct_ntfy_headers(
title=f"{thing_name} detected",
tag="rotating_light",
@ -140,4 +135,3 @@ def send_notification(data: str, headers: dict, url: str):
if url is None or data is None:
raise ValueError("url and data cannot be None")
httpx.post(url, data=data.encode("utf-8"), headers=headers)

View File

@ -5,6 +5,7 @@ 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,
@ -18,20 +19,23 @@ def plot_label(
view_scale: float = None,
font: int = cv2.FONT_HERSHEY_SIMPLEX,
):
# x1 and y1 are the top left corner of the box
# x2 and y2 are the bottom right corner of the box
# Example scaling: full_frame: 1 run_frame: 0.5 view_frame: 0.25
view_frame = cv2.resize(full_frame, (0, 0), fx=view_scale, fy=view_scale)
for thing in boxes:
cv2.rectangle(
# Image
view_frame,
# Start point
# Top left corner
(
int(thing["x1"] * (run_scale / view_scale)),
int(thing["y1"] * (run_scale / view_scale)),
int((thing["x1"] / run_scale) * view_scale),
int((thing["y1"] / run_scale) * view_scale),
),
# End point
# Bottom right corner
(
int(thing["x2"] * (run_scale / view_scale)),
int(thing["y2"] * (run_scale / view_scale)),
int((thing["x2"] / run_scale) * view_scale),
int((thing["y2"] / run_scale) * view_scale),
),
# Color
(0, 255, 0),
@ -45,8 +49,8 @@ def plot_label(
thing["label"],
# Origin
(
int(thing["x1"] * (run_scale / view_scale)),
int(thing["y1"] * (run_scale / view_scale)),
int((thing["x1"] / run_scale) * view_scale),
int((thing["y1"] / run_scale) * view_scale) - 10,
),
# Font
font,
@ -65,7 +69,7 @@ def recognize_face(
# opencv image
run_frame: np.ndarray = None,
) -> np.ndarray:
'''
"""
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
@ -85,7 +89,7 @@ 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
@ -99,9 +103,17 @@ def recognize_face(
# face_dataframes is a vanilla list of dataframes
try:
face_dataframes = DeepFace.find(run_frame, db_path=str(path_to_directory), enforce_detection=True, silent=True)
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.":
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:
@ -120,14 +132,18 @@ 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"],
}
# After some brief testing, it seems positve matches are > 0.3
# I have not seen any false positives, so there is no threashold yet
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}')
print(
f"Confindence: {distance}, filname: {path_to_image.name}, to_return: {to_return}"
)
return to_return
'''
"""
Example dataframe, for reference
identity (path to image) | source_x | source_y | source_w | source_h | VGG-Face_cosine (pretty much the confidence \_('_')_/)
'''
"""