2023-10-27 16:54:36 +01:00
import argparse
import os
import dotenv
from pathlib import Path
argparser = None
2023-10-27 17:33:05 +01:00
2023-10-27 16:54:36 +01:00
def set_argparse ( ) :
global argparser
if Path ( " .env " ) . is_file ( ) :
dotenv . load_dotenv ( )
print ( " Loaded .env file " )
else :
print ( " No .env file found " )
2023-10-27 17:52:33 +01:00
# One important thing to consider is that most function parameters are optional and have a default value
# However, with argparse, those are never used since a argparse always passes something, even if it's None
2023-10-27 16:54:36 +01:00
argparser = argparse . ArgumentParser (
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
2024-02-16 19:01:02 +00:00
epilog = " For env bool options, setting them to anything except for an empty string will enable them. " ,
2023-10-27 16:54:36 +01:00
)
2023-10-27 17:52:33 +01:00
video_options = argparser . add_argument_group ( " Video Options " )
stream_source = video_options . add_mutually_exclusive_group ( )
stream_source . add_argument (
" --rtsp-url " ,
2024-02-11 03:16:11 +00:00
action = " append " ,
# If RTSP_URL is in the environment, use it, otherwise just use a blank list
# This may cause problems down the road, but if it does, env for this can be removed
2024-02-16 19:01:02 +00:00
default = [ os . environ [ " RTSP_URL " ] ]
if " RTSP_URL " in os . environ and os . environ [ " RTSP_URL " ] != " "
else [ ] ,
2023-10-27 17:52:33 +01:00
type = str ,
help = " RTSP camera URL " ,
)
stream_source . add_argument (
" --capture-device " ,
2024-02-11 03:16:11 +00:00
action = " append " ,
# If CAPTURE_DEVICE is in the environment, use it, otherwise just use a blank list
# If __main__.py detects that no capture device or remote stream is set, it will default to 0
2024-02-16 19:01:02 +00:00
default = [ int ( os . environ [ " CAPTURE_DEVICE " ] ) ]
if " CAPTURE_DEVICE " in os . environ and os . environ [ " CAPTURE_DEVICE " ] != " "
else [ ] ,
2023-10-27 17:52:33 +01:00
type = int ,
help = " Capture device number " ,
)
video_options . add_argument (
2023-10-27 16:54:36 +01:00
" --run-scale " ,
# 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,
else 1 ,
type = float ,
help = " The scale to run the detection at, default is 0.25 " ,
)
2023-10-27 17:52:33 +01:00
video_options . add_argument (
2023-10-27 16:54:36 +01:00
" --view-scale " ,
# 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,
else 1 ,
type = float ,
help = " The scale to view the detection at, default is 0.75 " ,
)
2023-10-27 17:52:33 +01:00
video_options . add_argument (
2023-10-27 16:54:36 +01:00
" --no-display " ,
default = os . environ [ " NO_DISPLAY " ]
2024-02-16 18:34:39 +00:00
if " NO_DISPLAY " in os . environ
and os . environ [ " NO_DISPLAY " ] != " "
and os . environ [ " NO_DISPLAY " ] . lower ( ) != " false "
2023-10-27 16:54:36 +01:00
else False ,
action = " store_true " ,
help = " Don ' t display the video feed " ,
)
2023-12-03 03:23:42 +00:00
video_options . add_argument (
2024-02-16 19:01:02 +00:00
" -c " ,
" --force-disable-tensorflow-gpu " ,
2023-12-03 03:23:42 +00:00
default = os . environ [ " FORCE_DISABLE_TENSORFLOW_GPU " ]
2024-02-16 19:01:02 +00:00
if " FORCE_DISABLE_TENSORFLOW_GPU " in os . environ
2024-02-16 18:34:39 +00:00
and os . environ [ " FORCE_DISABLE_TENSORFLOW_GPU " ] != " "
and os . environ [ " FORCE_DISABLE_TENSORFLOW_GPU " ] . lower ( ) != " false "
2023-12-03 03:23:42 +00:00
else False ,
action = " store_true " ,
help = " Force disable tensorflow GPU through env since sometimes it ' s not worth it to install cudnn and whatnot " ,
)
2023-10-27 16:54:36 +01:00
notifcation_services = argparser . add_argument_group ( " Notification Services " )
notifcation_services . add_argument (
" --ntfy-url " ,
default = os . environ [ " NTFY_URL " ]
if " NTFY_URL " in os . environ and os . environ [ " NTFY_URL " ] != " "
2024-03-04 00:03:25 +00:00
# This is None but there is a default set in notify.py
2023-10-27 17:08:17 +01:00
else None ,
2023-10-27 16:54:36 +01:00
type = str ,
help = " The URL to send notifications to " ,
)
2023-12-22 21:22:01 +00:00
# Various timers
2023-10-27 16:54:36 +01:00
timers = argparser . add_argument_group ( " Timers " )
timers . add_argument (
" --detection-duration " ,
default = os . environ [ " DETECTION_DURATION " ]
if " DETECTION_DURATION " in os . environ and os . environ [ " DETECTION_DURATION " ] != " "
else 2 ,
type = int ,
help = " The duration (in seconds) that an object must be detected for before sending a notification " ,
)
timers . add_argument (
" --detection-window " ,
default = os . environ [ " DETECTION_WINDOW " ]
if " DETECTION_WINDOW " in os . environ and os . environ [ " DETECTION_WINDOW " ] != " "
else 15 ,
type = int ,
help = " The time (seconds) before the detection duration resets " ,
)
timers . add_argument (
" --notification-window " ,
default = os . environ [ " NOTIFICATION_WINDOW " ]
if " NOTIFICATION_WINDOW " in os . environ
and os . environ [ " NOTIFICATION_WINDOW " ] != " "
else 30 ,
type = int ,
help = " The time (seconds) before another notification can be sent " ,
)
2023-10-27 17:52:33 +01:00
face_recognition = argparser . add_argument_group ( " Face Recognition options " )
face_recognition . add_argument (
" --faces-directory " ,
default = os . environ [ " FACES_DIRECTORY " ]
if " FACES_DIRECTORY " in os . environ and os . environ [ " FACES_DIRECTORY " ] != " "
else " faces " ,
type = str ,
help = " The directory to store the faces. Can either contain images or subdirectories with images, the latter being the preferred method " , # noqa: E501
)
face_recognition . add_argument (
" --face-confidence-threshold " ,
default = os . environ [ " FACE_CONFIDENCE_THRESHOLD " ]
if " FACE_CONFIDENCE_THRESHOLD " in os . environ
and os . environ [ " FACE_CONFIDENCE_THRESHOLD " ] != " "
else 0.3 ,
type = float ,
help = " The confidence (currently cosine similarity) threshold to use for face recognition " ,
)
face_recognition . add_argument (
" --no-remove-representations " ,
default = os . environ [ " NO_REMOVE_REPRESENTATIONS " ]
if " NO_REMOVE_REPRESENTATIONS " in os . environ
and os . environ [ " NO_REMOVE_REPRESENTATIONS " ] != " "
2024-02-16 18:34:39 +00:00
and os . environ [ " NO_REMOVE_REPRESENTATIONS " ] . lower ( ) != " false "
2023-10-27 17:52:33 +01:00
else False ,
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
)
object_detection = argparser . add_argument_group ( " Object Detection options " )
object_detection . add_argument (
" --detect-object " ,
2023-12-24 22:07:53 +00:00
action = " append " ,
2024-02-11 03:16:11 +00:00
# Stuff is appended to default, as far as I can tell
2023-10-27 17:52:33 +01:00
default = [ ] ,
type = str ,
help = " The object(s) to detect. Must be something the model is trained to detect " ,
)
object_detection . add_argument (
" --object-confidence-threshold " ,
default = os . environ [ " OBJECT_CONFIDENCE_THRESHOLD " ]
if " OBJECT_CONFIDENCE_THRESHOLD " in os . environ
2024-02-16 19:01:02 +00:00
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 ,
2023-10-27 17:52:33 +01:00
type = float ,
help = " The confidence threshold to use " ,
)
2024-02-16 18:34:39 +00:00
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 ,
)
2023-10-27 16:54:36 +01:00
# return argparser
2023-10-27 17:33:05 +01:00
2023-10-27 16:54:36 +01:00
# This will run when this file is imported
2023-10-27 17:33:05 +01:00
set_argparse ( )