Multiple sources can now be used

Added `--fake-second-source` to help with debugging
This commit is contained in:
slashtechno 2024-02-16 12:34:39 -06:00
parent 494708a376
commit 8f500e0186
Signed by: slashtechno
GPG Key ID: 8EC1D9D9286C2B17
3 changed files with 61 additions and 24 deletions

2
.vscode/launch.json vendored
View File

@ -10,7 +10,7 @@
"request": "launch", "request": "launch",
"module": "wyzely_detect", "module": "wyzely_detect",
"args": [ "args": [
"--run-scale", "0.25", "--view-scale", "0.5", "--no-remove-representations" "--run-scale", "0.25", "--view-scale", "0.5", "--no-remove-representations", "--fake-second-source"
], ],
"justMyCode": true "justMyCode": true
}, },

View File

@ -59,6 +59,17 @@ def main():
"devices": [cv2.VideoCapture(device) for device in args.capture_device], "devices": [cv2.VideoCapture(device) for device in args.capture_device],
} }
if args.fake_second_source:
try:
video_sources["devices"].append(video_sources["devices"][0])
except KeyError:
print("No capture device to use as second source. Trying stream.")
try:
video_sources["devices"].append(video_sources["devices"][0])
except KeyError:
print("No stream to use as a second source")
# When the code tries to resize the nonexistent capture device 1, the program will fail
# Eliminate lag by setting the buffer size to 1 # Eliminate lag by setting the buffer size to 1
# This makes it so that the video capture will only grab the most recent frame # This makes it so that the video capture will only grab the most recent frame
# However, this means that the video may be choppy # However, this means that the video may be choppy
@ -74,6 +85,7 @@ def main():
pretty_table = PrettyTable(field_names=["Source Type", "Resolution"]) pretty_table = PrettyTable(field_names=["Source Type", "Resolution"])
for source_type, sources in video_sources.items(): for source_type, sources in video_sources.items():
for source in sources: for source in sources:
# TODO: Add check to see if resolution is 0x0, and if it is, print a warning or just fail
pretty_table.add_row( pretty_table.add_row(
[source_type, f"{source.get(cv2.CAP_PROP_FRAME_WIDTH)}x{source.get(cv2.CAP_PROP_FRAME_HEIGHT)}"] [source_type, f"{source.get(cv2.CAP_PROP_FRAME_WIDTH)}x{source.get(cv2.CAP_PROP_FRAME_HEIGHT)}"]
) )
@ -83,31 +95,36 @@ def main():
print("Beginning video capture...") print("Beginning video capture...")
while True: while True:
# Grab a single frame of video # Grab a single frame of video
ret, frame = video_capture.read() frames = []
# frames = [source.read() for sources in video_sources.values() for source in sources]
for list_of_sources in video_sources.values():
frames.extend([source.read()[1] for source in list_of_sources])
frames_to_show = []
for frame in frames:
frames_to_show.append(utils.process_footage(
frame = frame,
run_scale = args.run_scale,
view_scale = args.view_scale,
frame_to_show = utils.process_footage( faces_directory=Path(args.faces_directory),
frame = frame, face_confidence_threshold=args.face_confidence_threshold,
run_scale = args.run_scale, no_remove_representations=args.no_remove_representations,
view_scale = args.view_scale,
faces_directory=Path(args.faces_directory), detection_window=args.detection_window,
face_confidence_threshold=args.face_confidence_threshold, detection_duration=args.detection_duration,
no_remove_representations=args.no_remove_representations, notification_window=args.notification_window,
detection_window=args.detection_window, ntfy_url=args.ntfy_url,
detection_duration=args.detection_duration,
notification_window=args.notification_window,
ntfy_url=args.ntfy_url, model=model,
detect_object=args.detect_object,
model=model, object_confidence_threshold=args.object_confidence_threshold,
detect_object=args.detect_object, ))
object_confidence_threshold=args.object_confidence_threshold,
)
# Display the resulting frame # Display the resulting frame
# TODO: When multi-camera support is added, this needs to be changed to allow all feeds # TODO: When multi-camera support is added, this needs to be changed to allow all feeds
if not args.no_display: if not args.no_display:
cv2.imshow("Video", frame_to_show) for i, frame_to_show in enumerate(frames_to_show):
cv2.imshow(f"Video {i}", frame_to_show)
# Hit 'q' on the keyboard to quit! # Hit 'q' on the keyboard to quit!
if cv2.waitKey(1) & 0xFF == ord("q"): if cv2.waitKey(1) & 0xFF == ord("q"):
@ -115,7 +132,7 @@ def main():
# Release handle to the webcam # Release handle to the webcam
print("Releasing video capture") print("Releasing video capture")
video_capture.release() [source.release() for sources in video_sources.values() for source in sources]
cv2.destroyAllWindows() cv2.destroyAllWindows()

View File

@ -21,7 +21,7 @@ def set_argparse():
argparser = argparse.ArgumentParser( argparser = argparse.ArgumentParser(
prog="Wyzely Detect", prog="Wyzely Detect",
description="Recognize faces/objects in a video stream (from a webcam or a security camera) and send notifications to your devices", # noqa: E501 description="Recognize faces/objects in a video stream (from a webcam or a security camera) and send notifications to your devices", # noqa: E501
epilog=":)", epilog="For env bool options, setting them to anything except for an empty string will enable them."
) )
@ -69,7 +69,9 @@ def set_argparse():
video_options.add_argument( video_options.add_argument(
"--no-display", "--no-display",
default=os.environ["NO_DISPLAY"] default=os.environ["NO_DISPLAY"]
if "NO_DISPLAY" in os.environ and os.environ["NO_DISPLAY"] != "" if "NO_DISPLAY" in os.environ
and os.environ["NO_DISPLAY"] != ""
and os.environ["NO_DISPLAY"].lower() != "false"
else False, else False,
action="store_true", action="store_true",
help="Don't display the video feed", help="Don't display the video feed",
@ -78,7 +80,9 @@ def set_argparse():
'-c', '-c',
'--force-disable-tensorflow-gpu', '--force-disable-tensorflow-gpu',
default=os.environ["FORCE_DISABLE_TENSORFLOW_GPU"] default=os.environ["FORCE_DISABLE_TENSORFLOW_GPU"]
if "FORCE_DISABLE_TENSORFLOW_GPU" in os.environ and os.environ["FORCE_DISABLE_TENSORFLOW_GPU"] != "" if "FORCE_DISABLE_TENSORFLOW_GPU" in os.environ
and os.environ["FORCE_DISABLE_TENSORFLOW_GPU"] != ""
and os.environ["FORCE_DISABLE_TENSORFLOW_GPU"].lower() != "false"
else False, else False,
action="store_true", action="store_true",
help="Force disable tensorflow GPU through env since sometimes it's not worth it to install cudnn and whatnot", help="Force disable tensorflow GPU through env since sometimes it's not worth it to install cudnn and whatnot",
@ -146,6 +150,7 @@ def set_argparse():
default=os.environ["NO_REMOVE_REPRESENTATIONS"] default=os.environ["NO_REMOVE_REPRESENTATIONS"]
if "NO_REMOVE_REPRESENTATIONS" in os.environ if "NO_REMOVE_REPRESENTATIONS" in os.environ
and os.environ["NO_REMOVE_REPRESENTATIONS"] != "" and os.environ["NO_REMOVE_REPRESENTATIONS"] != ""
and os.environ["NO_REMOVE_REPRESENTATIONS"].lower() != "false"
else False, else False,
action="store_true", action="store_true",
help="Don't remove representations_<model>.pkl at the start of the program. Greatly improves startup time, but doesn't take into account changes to the faces directory since it was created", # noqa: E501 help="Don't remove representations_<model>.pkl at the start of the program. Greatly improves startup time, but doesn't take into account changes to the faces directory since it was created", # noqa: E501
@ -166,12 +171,27 @@ def set_argparse():
"--object-confidence-threshold", "--object-confidence-threshold",
default=os.environ["OBJECT_CONFIDENCE_THRESHOLD"] default=os.environ["OBJECT_CONFIDENCE_THRESHOLD"]
if "OBJECT_CONFIDENCE_THRESHOLD" in os.environ if "OBJECT_CONFIDENCE_THRESHOLD" in os.environ
and os.environ["OBJECT_CONFIDENCE_THRESHOLD"] != "" and os.environ["OBJECT_CONFIDENCE_THRESHOLD"] != ""
# I think this should always be a str so using lower shouldn't be a problem.
# Also, if the first check fails the rest shouldn't be run
and os.environ["OBJECT_CONFIDENCE_THRESHOLD"].lower() != "false"
else 0.6, else 0.6,
type=float, type=float,
help="The confidence threshold to use", help="The confidence threshold to use",
) )
debug = argparser.add_argument_group("Debug options")
debug.add_argument(
"--fake-second-source",
help="Duplicate the first source and use it as a second source. Capture device takes priority.",
action="store_true",
default=os.environ["FAKE_SECOND_SOURCE"]
if "FAKE_SECOND_SOURCE" in os.environ
and os.environ["FAKE_SECOND_SOURCE"] != ""
and os.environ["FAKE_SECOND_SOURCE"].lower() != "false"
else False,
)
# return argparser # return argparser