              default_detector = "s3fd"
              default_aligner = "fan"
  
          argument_list = []
          argument_list.append({"opts": ("-D", "--detector"),
                                "action": Radio,
                                "type": str.lower,
                                "choices":  PluginLoader.get_available_extractors("detect"),
                                "default": default_detector,
                                "group": "Plugins",
                                "help": "R|Detector to use. Some of these have configurable "
                                        "settings in '/config/extract.ini' or 'Settings > Configure "
                                        "Extract 'Plugins':"
                                        "\nL|cv2-dnn: A CPU only extractor which is the least "
                                        "reliable and least resource intensive. Use this if not "
                                        "using a GPU and time is important."
                                        "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses "
                                        "fewer resources than other GPU detectors but can often "
                                        "return more false positives."
                                        "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can "
                                        "detect more faces and fewer false positives than other "
                                        "GPU detectors, but is a lot more resource intensive."})
          argument_list.append({"opts": ("-A", "--aligner"),
                                "action": Radio,
                                "type": str.lower,
                                "choices": PluginLoader.get_available_extractors("align"),
                                "default": default_aligner,
                                "group": "Plugins",
                                "help": "R|Aligner to use."
                                        "\nL|cv2-dnn: A CPU only landmark detector. Faster, less "
                                        "resource intensive, but less accurate. Only use this if "
                                        "not using a GPU and time is important."
                                        "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
          argument_list.append({"opts": ("-M", "--masker"),
                                "action": Radio,
                                "type": str.lower,
                                "choices": PluginLoader.get_available_extractors("mask"),
                                "default": "components",
                                "group": "Plugins",
                                "help": "R|Masker to use."
                                        "\nL|none: An array of all ones is created to provide a 4th "
                                        "channel that will not mask any portion of the image."
                                        "\nL|components: Mask designed to provide facial "
                                        "segmentation based on the positioning of landmark "
                                        "locations. A convex hull is constructed around the "
                                        "exterior of the landmarks to create a mask."
                                        "\nL|extended: Mask designed to provide facial segmentation "
                                        "based on the positioning of landmark locations. A convex "
                                        "hull is constructed around the exterior of the landmarks "
                                        "and the mask is extended upwards onto the forehead."
                                        "\nL|vgg-clear: Mask designed to provide smart segmentation "
                                        "of mostly frontal faces clear of obstructions.  Profile "
                                        "faces and obstructions may result in sub-par performance."
                                        "\nL|vgg-obstructed: Mask designed to provide smart "
                                        "segmentation of mostly frontal faces. The mask model has "
                                        "been specifically trained to recognize some facial "
                                        "obstructions (hands and eyeglasses). Profile faces may "
                                        "result in sub-par performance."
                                        "\nL|unet-dfl: Mask designed to provide smart segmentation "
                                        "of mostly frontal faces. The mask model has been trained "
                                        "by community members and will need testing for further "
                                        "description. Profile faces may result in sub-par "
                                        "performance."})
          argument_list.append({"opts": ("-nm", "--normalization"),
                                "action": Radio,
                                "type": str.lower,
                                "dest": "normalization",
                                "choices": ["none", "clahe", "hist", "mean"],
                                "default": "none",
                                "group": "plugins",
                                "help": "R|Performing normalization can help the aligner better "
                                        "align faces with difficult lighting conditions at an "
                                        "extraction speed cost. Different methods will yield "
                                        "different results on different sets. NB: This does not "
                                        "impact the output face, just the input to the aligner."
                                        "\nL|none: Don't perform normalization on the face."
                                        "\nL|clahe: Perform Contrast Limited Adaptive Histogram "
                                        "Equalization on the face."
                                        "\nL|hist: Equalize the histograms on the RGB channels."
                                        "\nL|mean: Normalize the face colors to the mean."})
          argument_list.append({"opts": ("-r", "--rotate-images"),
                                "type": str,
                                "dest": "rotate_images",
                                "default": None,
                                "group": "plugins",
                                "help": "If a face isn't found, rotate the images to try to find a "
                                        "face. Can find more faces at the cost of extraction speed. "
                                        "Pass in a single number to use increments of that size up "
                                        "to 360, or pass in a list of numbers to enumerate exactly "
                                        "what angles to check"})
          argument_list.append({"opts": ("-min", "--min-size"),
                                "type": int,
                                "action": Slider,
                                "dest": "min_size",
                                "min_max": (0, 1080),
                                "default": 0,
                                "rounding": 20,
                                "group": "Face Processing",
                                "help": "Filters out faces detected below this size. Length, in "
                                        "pixels across the diagonal of the bounding box. Set to 0 "
                                        "for off"})
          argument_list.append({"opts": ("-n", "--nfilter"),
                                "action": FilesFullPaths,
                                "filetypes": "image",
                                "dest": "nfilter",
                                "nargs": "+",
                                "default": None,
                                "group": "Face Processing",
                                "help": "Optionally filter out people who you do not wish to "
                                        "process by passing in an image of that person. Should be a "
                                        "front portrait with a single person in the image. Multiple "
                                        "images can be added space separated. NB: Using face filter "
                                        "will significantly decrease extraction speed and its "
                                        "accuracy cannot be guaranteed."})
          argument_list.append({"opts": ("-f", "--filter"),
                                "action": FilesFullPaths,
                                "filetypes": "image",
                                "dest": "filter",
                                "nargs": "+",
                                "default": None,
                                "group": "Face Processing",
                                "help": "Optionally select people you wish to process by passing in "
                                        "an image of that person. Should be a front portrait with a "
                                        "single person in the image. Multiple images can be added "
                                        "space separated. NB: Using face filter will significantly "
                                        "decrease extraction speed and its accuracy cannot be "
                                        "guaranteed."})
          argument_list.append({"opts": ("-l", "--ref_threshold"),
                                "action": Slider,
                                "min_max": (0.01, 0.99),
                                "rounding": 2,
                                "type": float,
                                "dest": "ref_threshold",
                                "default": 0.4,
                                "group": "Face Processing",
                                "help": "For use with the optional nfilter/filter files. Threshold "
                                        "for positive face recognition. Lower values are stricter. "
                                        "NB: Using face filter will significantly decrease "
                                        "extraction speed and its accuracy cannot be "
                                        "guaranteed."})
          argument_list.append({"opts": ("-bt", "--blur-threshold"),
                                "type": float,
                                "action": Slider,
                                "min_max": (0.0, 100.0),
                                "rounding": 1,
                                "dest": "blur_thresh",
                                "default": 0.0,
                                "group": "Face Processing",
                                "help": "Automatically discard images blurrier than the specified "
                                        "threshold. Discarded images are moved into a \"blurry\" "
                                        "sub-folder. Lower values allow more blur. Set to 0.0 to "
                                        "turn off."})
          argument_list.append({"opts": ("-een", "--extract-every-n"),
                                "type": int,
                                "action": Slider,
                                "dest": "extract_every_n",
                                "min_max": (1, 100),
                                "default": 1,
                                "rounding": 1,
                                "group": "output",
                                "help": "Extract every 'nth' frame. This option will skip frames "
                                        "when extracting faces. For example a value of 1 will "
                                        "extract faces from every frame, a value of 10 will extract "
                                        "faces from every 10th frame."})
          argument_list.append({"opts": ("-sz", "--size"),
                                "type": int,
                                "action": Slider,
                                "min_max": (128, 512),
                                "default": 256,
                                "rounding": 64,
                                "group": "output",
                                "help": "The output size of extracted faces. Make sure that the "
                                        "model you intend to train supports your required size. "
                                        "This will only need to be changed for hi-res models."})
          argument_list.append({"opts": ("-si", "--save-interval"),
                                "dest": "save_interval",
                                "type": int,
                                "action": Slider,
                                "min_max": (0, 1000),
                                "rounding": 10,
                                "default": 0,
                                "group": "output",
                                "help": "Automatically save the alignments file after a set amount "
                                        "of frames. By default the alignments file is only saved at "
                                        "the end of the extraction process. NB: If extracting in 2 "
                                        "passes then the alignments file will only start to be "
                                        "saved out during the second pass. WARNING: Don't interrupt "
                                        "the script when writing the file because it might get "
                                        "corrupted. Set to 0 to turn off"})
          argument_list.append({"opts": ("-dl", "--debug-landmarks"),
                                "action": "store_true",
                                "dest": "debug_landmarks",
                                "group": "output",
                                "default": False,
                                "help": "Draw landmarks on the ouput faces for debugging purposes."})
          argument_list.append({"opts": ("-sp", "--singleprocess"),
                                "action": "store_true",
                                "default": False,
                                "backend": "nvidia",
                                "group": "settings",
                                "help": "Don't run extraction in parallel. Will run detection first "
                                        "then alignment (2 passes). Useful if VRAM is at a "
                                        "premium."})
          argument_list.append({"opts": ("-s", "--skip-existing"),
                                "action": "store_true",
                                "dest": "skip_existing",
                                "group": "settings",
                                "default": False,
                                "help": "Skips frames that have already been extracted and exist in "
                                        "the alignments file"})
          argument_list.append({"opts": ("-sf", "--skip-existing-faces"),
                                "action": "store_true",
                                "dest": "skip_faces",
                                "group": "settings",
                                "default": False,
                                "help": "Skip frames that already have detected faces in the "
                                        "alignments file"})
          return argument_list
  
  
  class ConvertArgs(ExtractConvertArgs):
      """ Class to parse the command line arguments for conversion.
 
</s> remove         argument_list.append({"opts": ("-w", "--writer"),
                              "action": Radio,
                              "type": str,
                              "choices": PluginLoader.get_available_convert_plugins("writer",
                                                                                    False),
                              "group": "plugins",
                              "default": "opencv",
                              "help": "R|The plugin to use to output the converted images. The "
                                      "writers are configurable in '/config/convert.ini' or "
                                      "'Settings > Configure Convert Plugins:'"
                                      "\nL|ffmpeg: [video] Writes out the convert straight to "
                                      "video. When the input is a series of images then the "
                                      "'-ref' (--reference-video) parameter must be set."
                                      "\nL|gif: [animated image] Create an animated gif."
                                      "\nL|opencv: [images] The fastest image writer, but less "
                                      "options and formats than other plugins."
                                      "\nL|pillow: [images] Slower than opencv, but has more "
                                      "options and supports more formats."})
        argument_list.append({"opts": ("-osc", "--output-scale"),
                              "dest": "output_scale",
                              "action": Slider,
                              "type": int,
                              "default": 100,
                              "min_max": (25, 400),
                              "rounding": 1,
                              "group": "Frame Processing",
                              "help": "Scale the final output frames by this amount. 100%% will "
                                      "output the frames at source dimensions. 50%% at half size "
                                      "200%% at double size"})
        argument_list.append({"opts": ("-fr", "--frame-ranges"),
                              "nargs": "+",
                              "type": str,
                              "group": "Frame Processing",
                              "help": "Frame ranges to apply transfer to e.g. For frames 10 to 50 "
                                      "and 90 to 100 use --frame-ranges 10-50 90-100. Frames "
                                      "falling outside of the selected range will be discarded "
                                      "unless '-k' (--keep-unchanged) is selected. NB: If you are "
                                      "converting from images, then the filenames must end with "
                                      "the frame-number!"})
        argument_list.append({"opts": ("-a", "--input-aligned-dir"),
                              "action": DirFullPaths,
                              "dest": "input_aligned_dir",
                              "group": "Face Processing",
                              "default": None,
                              "help": "If you have not cleansed your alignments file, then you "
                                      "can filter out faces by defining a folder here that "
                                      "contains the faces extracted from your input files/video. "
                                      "If this folder is defined, then only faces that exist "
                                      "within your alignments file and also exist within the "
                                      "specified folder will be converted. Leaving this blank "
                                      "will convert all faces that exist within the alignments "
                                      "file."})
        argument_list.append({"opts": ("-n", "--nfilter"),
                              "action": FilesFullPaths,
                              "filetypes": "image",
                              "dest": "nfilter",
                              "nargs": "+",
                              "default": None,
                              "group": "Face Processing",
                              "help": "Optionally filter out people who you do not wish to "
                                      "process by passing in an image of that person. Should be a "
                                      "front portrait with a single person in the image. Multiple "
                                      "images can be added space separated. NB: Using face filter "
                                      "will significantly decrease extraction speed and its "
                                      "accuracy cannot be guaranteed."})
        argument_list.append({"opts": ("-f", "--filter"),
                              "action": FilesFullPaths,
                              "filetypes": "image",
                              "dest": "filter",
                              "nargs": "+",
                              "default": None,
                              "group": "Face Processing",
                              "help": "Optionally select people you wish to process by passing in "
                                      "an image of that person. Should be a front portrait with a "
                                      "single person in the image. Multiple images can be added "
                                      "space separated. NB: Using face filter will significantly "
                                      "decrease extraction speed and its accuracy cannot be "
                                      "guaranteed."})
        argument_list.append({"opts": ("-l", "--ref_threshold"),
                              "action": Slider,
                              "min_max": (0.01, 0.99),
                              "rounding": 2,
                              "type": float,
                              "dest": "ref_threshold",
                              "default": 0.4,
                              "group": "Face Processing",
                              "help": "For use with the optional nfilter/filter files. Threshold "
                                      "for positive face recognition. Lower values are stricter. "
                                      "NB: Using face filter will significantly decrease "
                                      "extraction speed and its accuracy cannot be "
                                      "guaranteed."})

        argument_list.append({"opts": ("-j", "--jobs"),
                              "dest": "jobs",
                              "action": Slider,
                              "group": "settings",
                              "type": int,
                              "default": 0,
                              "min_max": (0, 40),
                              "rounding": 1,
                              "help": "The maximum number of parallel processes for performing "
                                      "conversion. Converting images is system RAM heavy so it is "
                                      "possible to run out of memory if you have a lot of "
                                      "processes and not enough RAM to accommodate them all. "
                                      "Setting this to 0 will use the maximum available. No "
                                      "matter what you set this to, it will never attempt to use "
                                      "more processes than are available on your system. If "
                                      "singleprocess is enabled this setting will be ignored."})
        argument_list.append({"opts": ("-g", "--gpus"),
                              "type": int,
                              "backend": "nvidia",
                              "action": Slider,
                              "min_max": (1, 10),
                              "rounding": 1,
                              "group": "settings",
                              "default": 1,
                              "help": "Number of GPUs to use for conversion"})
        argument_list.append({"opts": ("-t", "--trainer"),
                              "type": str.lower,
                              "choices": PluginLoader.get_available_models(),
                              "group": "settings",
                              "help": "[LEGACY] This only needs to be selected if a legacy "
                                      "model is being loaded or if there are multiple models in "
                                      "the model folder"})
        argument_list.append({"opts": ("-k", "--keep-unchanged"),
                              "action": "store_true",
                              "dest": "keep_unchanged",
                              "group": "Frame Processing",
                              "default": False,
                              "help": "When used with --frame-ranges outputs the unchanged frames "
                                      "that are not processed instead of discarding them."})
        argument_list.append({"opts": ("-s", "--swap-model"),
                              "action": "store_true",
                              "dest": "swap_model",
                              "group": "settings",
                              "default": False,
                              "help": "Swap the model. Instead converting from of A -> B, "
                                      "converts B -> A"})
        argument_list.append({"opts": ("-sp", "--singleprocess"),
                              "action": "store_true",
                              "group": "settings",
                              "default": False,
                              "help": "Disable multiprocessing. Slower but less resource "
                                      "intensive."})
 </s> add         argument_list.append({
            "opts": ("-w", "--writer"),
            "action": Radio,
            "type": str,
            "choices": PluginLoader.get_available_convert_plugins("writer", False),
            "group": "plugins",
            "default": "opencv",
            "help": "R|The plugin to use to output the converted images. The writers are "
                    "configurable in '/config/convert.ini' or 'Settings > Configure Convert "
                    "Plugins:'"
                    "\nL|ffmpeg: [video] Writes out the convert straight to video. When the input "
                    "is a series of images then the '-ref' (--reference-video) parameter must be "
                    "set."
                    "\nL|gif: [animated image] Create an animated gif."
                    "\nL|opencv: [images] The fastest image writer, but less options and formats "
                    "than other plugins."
                    "\nL|pillow: [images] Slower than opencv, but has more options and supports "
                    "more formats."})
        argument_list.append({
            "opts": ("-osc", "--output-scale"),
            "dest": "output_scale",
            "action": Slider,
            "type": int,
            "default": 100,
            "min_max": (25, 400),
            "rounding": 1,
            "group": "Frame Processing",
            "help": "Scale the final output frames by this amount. 100%% will output the frames "
                    "at source dimensions. 50%% at half size 200%% at double size"})
        argument_list.append({
            "opts": ("-fr", "--frame-ranges"),
            "nargs": "+",
            "type": str,
            "group": "Frame Processing",
            "help": "Frame ranges to apply transfer to e.g. For frames 10 to 50 and 90 to 100 use "
                    "--frame-ranges 10-50 90-100. Frames falling outside of the selected range "
                    "will be discarded unless '-k' (--keep-unchanged) is selected. NB: If you are "
                    "converting from images, then the filenames must end with the frame-number!"})
        argument_list.append({
            "opts": ("-a", "--input-aligned-dir"),
            "action": DirFullPaths,
            "dest": "input_aligned_dir",
            "group": "Face Processing",
            "default": None,
            "help": "If you have not cleansed your alignments file, then you can filter out faces "
                    "by defining a folder here that contains the faces extracted from your input "
                    "files/video. If this folder is defined, then only faces that exist within "
                    "your alignments file and also exist within the specified folder will be "
                    "converted. Leaving this blank will convert all faces that exist within the "
                    "alignments file."})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-j", "--jobs"),
            "dest": "jobs",
            "action": Slider,
            "group": "settings",
            "type": int,
            "default": 0,
            "min_max": (0, 40),
            "rounding": 1,
            "help": "The maximum number of parallel processes for performing conversion. "
                    "Converting images is system RAM heavy so it is possible to run out of memory "
                    "if you have a lot of processes and not enough RAM to accommodate them all. "
                    "Setting this to 0 will use the maximum available. No matter what you set "
                    "this to, it will never attempt to use more processes than are available on "
                    "your system. If singleprocess is enabled this setting will be ignored."})
        argument_list.append({
            "opts": ("-g", "--gpus"),
            "type": int,
            "backend": "nvidia",
            "action": Slider,
            "min_max": (1, 10),
            "rounding": 1,
            "group": "settings",
            "default": 1,
            "help": "Number of GPUs to use for conversion"})
        argument_list.append({
            "opts": ("-t", "--trainer"),
            "type": str.lower,
            "choices": PluginLoader.get_available_models(),
            "group": "settings",
            "help": "[LEGACY] This only needs to be selected if a legacy model is being loaded or "
                    "if there are multiple models in the model folder"})
        argument_list.append({
            "opts": ("-k", "--keep-unchanged"),
            "action": "store_true",
            "dest": "keep_unchanged",
            "group": "Frame Processing",
            "default": False,
            "help": "When used with --frame-ranges outputs the unchanged frames that are not "
                    "processed instead of discarding them."})
        argument_list.append({
            "opts": ("-s", "--swap-model"),
            "action": "store_true",
            "dest": "swap_model",
            "group": "settings",
            "default": False,
            "help": "Swap the model. Instead converting from of A -> B, converts B -> A"})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "group": "settings",
            "default": False,
            "help": "Disable multiprocessing. Slower but less resource intensive."}) </s> remove         argument_list.append({"opts": ("-ref", "--reference-video"),
                              "action": FileFullPaths,
                              "dest": "reference_video",
                              "filetypes": "video",
                              "type": str,
                              "group": "data",
                              "help": "Only required if converting from images to video. Provide "
                                      "The original video that the source frames were extracted "
                                      "from (for extracting the fps and audio)."})
        argument_list.append({"opts": ("-m", "--model-dir"),
                              "action": DirFullPaths,
                              "dest": "model_dir",
                              "required": True,
                              "group": "data",
                              "help": "Model directory. The directory containing the trained "
                                      "model you wish to use for conversion."})
 </s> add         argument_list.append({
            "opts": ("-ref", "--reference-video"),
            "action": FileFullPaths,
            "dest": "reference_video",
            "filetypes": "video",
            "type": str,
            "group": "data",
            "help": "Only required if converting from images to video. Provide The original video "
                    "that the source frames were extracted from (for extracting the fps and "
                    "audio)."})
        argument_list.append({
            "opts": ("-m", "--model-dir"),
            "action": DirFullPaths,
            "dest": "model_dir",
            "required": True,
            "group": "data",
            "help": "Model directory. The directory containing the trained model you wish to use "
                    "for conversion."}) </s> remove         argument_list.append({"opts": ("-i", "--input-dir"),
                              "action": DirOrFileFullPaths,
                              "filetypes": "video",
                              "dest": "input_dir",
                              "required": True,
                              "group": "Data",
                              "help": "Input directory or video. Either a directory containing "
                                      "the image files you wish to process or path to a video "
                                      "file. NB: This should be the source video/frames NOT the "
                                      "source faces."})
        argument_list.append({"opts": ("-o", "--output-dir"),
                              "action": DirFullPaths,
                              "dest": "output_dir",
                              "required": True,
                              "group": "Data",
                              "help": "Output directory. This is where the converted files will "
                                      "be saved."})
        argument_list.append({"opts": ("-al", "--alignments"),
                              "action": FileFullPaths,
                              "filetypes": "alignments",
                              "type": str,
                              "dest": "alignments_path",
                              "group": "Data",
                              "help": "Optional path to an alignments file. Leave blank if the "
                                      "alignments file is at the default location."})
 </s> add         argument_list.append({
            "opts": ("-i", "--input-dir"),
            "action": DirOrFileFullPaths,
            "filetypes": "video",
            "dest": "input_dir",
            "required": True,
            "group": "Data",
            "help": "Input directory or video. Either a directory containing the image files you "
                    "wish to process or path to a video file. NB: This should be the source video/"
                    "frames NOT the source faces."})
        argument_list.append({
            "opts": ("-o", "--output-dir"),
            "action": DirFullPaths,
            "dest": "output_dir",
            "required": True,
            "group": "Data",
            "help": "Output directory. This is where the converted files will be saved."})
        argument_list.append({
            "opts": ("-al", "--alignments"),
            "action": FileFullPaths,
            "filetypes": "alignments",
            "type": str,
            "dest": "alignments_path",
            "group": "Data",
            "help": "Optional path to an alignments file. Leave blank if the alignments file is "
                    "at the default location."}) </s> remove         global_args.append({"opts": ("-C", "--configfile"),
                            "action": FileFullPaths,
                            "filetypes": "ini",
                            "type": str,
                            "group": "Global Options",
                            "help": "Optionally overide the saved config with the path to a "
                                    "custom config file."})
        global_args.append({"opts": ("-L", "--loglevel"),
                            "type": str.upper,
                            "dest": "loglevel",
                            "default": "INFO",
                            "choices": ("INFO", "VERBOSE", "DEBUG", "TRACE"),
                            "group": "Global Options",
                            "help": "Log level. Stick with INFO or VERBOSE unless you need to "
                                    "file an error report. Be careful with TRACE as it will "
                                    "generate a lot of data"})
        global_args.append({"opts": ("-LF", "--logfile"),
                            "action": SaveFileFullPaths,
                            "filetypes": 'log',
                            "type": str,
                            "dest": "logfile",
                            "group": "Global Options",
                            "help": "Path to store the logfile. Leave blank to store in the "
                                    "faceswap folder",
                            "default": None})
 </s> add         global_args.append({
            "opts": ("-C", "--configfile"),
            "action": FileFullPaths,
            "filetypes": "ini",
            "type": str,
            "group": "Global Options",
            "help": "Optionally overide the saved config with the path to a custom config file."})
        global_args.append({
            "opts": ("-L", "--loglevel"),
            "type": str.upper,
            "dest": "loglevel",
            "default": "INFO",
            "choices": ("INFO", "VERBOSE", "DEBUG", "TRACE"),
            "group": "Global Options",
            "help": "Log level. Stick with INFO or VERBOSE unless you need to file an error "
                    "report. Be careful with TRACE as it will generate a lot of data"})
        global_args.append({
            "opts": ("-LF", "--logfile"),
            "action": SaveFileFullPaths,
            "filetypes": 'log',
            "type": str,
            "dest": "logfile",
            "group": "Global Options",
            "help": "Path to store the logfile. Leave blank to store in the faceswap folder",
            "default": None}) </s> remove             "choices": ["dfl_full", "components", "extended", "predicted"],
 </s> add             "choices": get_available_masks() + ["predicted"],
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
              default_detector = "s3fd"
              default_aligner = "fan"
  
          argument_list = []
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
        argument_list.append({
            "opts": ("-D", "--detector"),
            "action": Radio,
            "type": str.lower,
            "choices":  PluginLoader.get_available_extractors("detect"),
            "default": default_detector,
            "group": "Plugins",
            "help": "R|Detector to use. Some of these have configurable settings in "
                    "'/config/extract.ini' or 'Settings > Configure Extract 'Plugins':"
                    "\nL|cv2-dnn: A CPU only extractor which is the least reliable and least "
                    "resource intensive. Use this if not using a GPU and time is important."
                    "\nL|mtcnn: Good detector. Fast on CPU, faster on GPU. Uses fewer resources "
                    "than other GPU detectors but can often return more false positives."
                    "\nL|s3fd: Best detector. Fast on GPU, slow on CPU. Can detect more faces and "
                    "fewer false positives than other GPU detectors, but is a lot more resource "
                    "intensive."})
        argument_list.append({
            "opts": ("-A", "--aligner"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("align"),
            "default": default_aligner,
            "group": "Plugins",
            "help": "R|Aligner to use."
                    "\nL|cv2-dnn: A CPU only landmark detector. Faster, less resource intensive, "
                    "but less accurate. Only use this if not using a GPU and time is important."
                    "\nL|fan: Best aligner. Fast on GPU, slow on CPU."})
        argument_list.append({
            "opts": ("-M", "--masker"),
            "action": Radio,
            "type": str.lower,
            "choices": PluginLoader.get_available_extractors("mask"),
            "default": "extended",
            "group": "Plugins",
            "help": "R|Masker to use. NB: Masker is not currently used by the rest of the process "
                    "but this will store a mask in the alignments file for use when it has been "
                    "implemented."
                    "\nL|none: An array of all ones is created to provide a 4th channel that will "
                    "not mask any portion of the image."
                    "\nL|components: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks to create a mask."
                    "\nL|extended: Mask designed to provide facial segmentation based on the "
                    "positioning of landmark locations. A convex hull is constructed around the "
                    "exterior of the landmarks and the mask is extended upwards onto the forehead."
                    "\nL|vgg-clear: Mask designed to provide smart segmentation of mostly frontal "
                    "faces clear of obstructions. Profile faces and obstructions may result in "
                    "sub-par performance."
                    "\nL|vgg-obstructed: Mask designed to provide smart segmentation of mostly "
                    "frontal faces. The mask model has been specifically trained to recognize "
                    "some facial obstructions (hands and eyeglasses). Profile faces may result in "
                    "sub-par performance."
                    "\nL|unet-dfl: Mask designed to provide smart segmentation of mostly frontal "
                    "faces. The mask model has been trained by community members and will need "
                    "testing for further description. Profile faces may result in sub-par "
                    "performance."})
        argument_list.append({
            "opts": ("-nm", "--normalization"),
            "action": Radio,
            "type": str.lower,
            "dest": "normalization",
            "choices": ["none", "clahe", "hist", "mean"],
            "default": "none",
            "group": "plugins",
            "help": "R|Performing normalization can help the aligner better align faces with "
                    "difficult lighting conditions at an extraction speed cost. Different methods "
                    "will yield different results on different sets. NB: This does not impact the "
                    "output face, just the input to the aligner."
                    "\nL|none: Don't perform normalization on the face."
                    "\nL|clahe: Perform Contrast Limited Adaptive Histogram Equalization on the "
                    "face."
                    "\nL|hist: Equalize the histograms on the RGB channels."
                    "\nL|mean: Normalize the face colors to the mean."})
        argument_list.append({
            "opts": ("-r", "--rotate-images"),
            "type": str,
            "dest": "rotate_images",
            "default": None,
            "group": "plugins",
            "help": "If a face isn't found, rotate the images to try to find a face. Can find "
                    "more faces at the cost of extraction speed. Pass in a single number to use "
                    "increments of that size up to 360, or pass in a list of numbers to enumerate "
                    "exactly what angles to check."})
        argument_list.append({
            "opts": ("-min", "--min-size"),
            "type": int,
            "action": Slider,
            "dest": "min_size",
            "min_max": (0, 1080),
            "default": 0,
            "rounding": 20,
            "group": "Face Processing",
            "help": "Filters out faces detected below this size. Length, in pixels across the "
                    "diagonal of the bounding box. Set to 0 for off"})
        argument_list.append({
            "opts": ("-n", "--nfilter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "nfilter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally filter out people who you do not wish to process by passing in an "
                    "image of that person. Should be a front portrait with a single person in the "
                    "image. Multiple images can be added space separated. NB: Using face filter "
                    "will significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-f", "--filter"),
            "action": FilesFullPaths,
            "filetypes": "image",
            "dest": "filter",
            "nargs": "+",
            "default": None,
            "group": "Face Processing",
            "help": "Optionally select people you wish to process by passing in an image of that "
                    "person. Should be a front portrait with a single person in the image. "
                    "Multiple images can be added space separated. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-l", "--ref_threshold"),
            "action": Slider,
            "min_max": (0.01, 0.99),
            "rounding": 2,
            "type": float,
            "dest": "ref_threshold",
            "default": 0.4,
            "group": "Face Processing",
            "help": "For use with the optional nfilter/filter files. Threshold for positive face "
                    "recognition. Lower values are stricter. NB: Using face filter will "
                    "significantly decrease extraction speed and its accuracy cannot be "
                    "guaranteed."})
        argument_list.append({
            "opts": ("-bt", "--blur-threshold"),
            "type": float,
            "action": Slider,
            "min_max": (0.0, 100.0),
            "rounding": 1,
            "dest": "blur_thresh",
            "default": 0.0,
            "group": "Face Processing",
            "help": "Automatically discard images blurrier than the specified threshold. "
                    "Discarded images are moved into a \"blurry\" sub-folder. Lower values allow "
                    "more blur. Set to 0.0 to turn off."})
        argument_list.append({
            "opts": ("-een", "--extract-every-n"),
            "type": int,
            "action": Slider,
            "dest": "extract_every_n",
            "min_max": (1, 100),
            "default": 1,
            "rounding": 1,
            "group": "output",
            "help": "Extract every 'nth' frame. This option will skip frames when extracting "
                    "faces. For example a value of 1 will extract faces from every frame, a value "
                    "of 10 will extract faces from every 10th frame."})
        argument_list.append({
            "opts": ("-sz", "--size"),
            "type": int,
            "action": Slider,
            "min_max": (128, 512),
            "default": 256,
            "rounding": 64,
            "group": "output",
            "help": "The output size of extracted faces. Make sure that the model you intend to "
                    "train supports your required size. This will only need to be changed for "
                    "hi-res models."})
        argument_list.append({
            "opts": ("-si", "--save-interval"),
            "dest": "save_interval",
            "type": int,
            "action": Slider,
            "min_max": (0, 1000),
            "rounding": 10,
            "default": 0,
            "group": "output",
            "help": "Automatically save the alignments file after a set amount of frames. By "
                    "default the alignments file is only saved at the end of the extraction "
                    "process. NB: If extracting in 2 passes then the alignments file will only "
                    "start to be saved out during the second pass. WARNING: Don't interrupt the "
                    "script when writing the file because it might get corrupted. Set to 0 to "
                    "turn off"})
        argument_list.append({
            "opts": ("-dl", "--debug-landmarks"),
            "action": "store_true",
            "dest": "debug_landmarks",
            "group": "output",
            "default": False,
            "help": "Draw landmarks on the ouput faces for debugging purposes."})
        argument_list.append({
            "opts": ("-sp", "--singleprocess"),
            "action": "store_true",
            "default": False,
            "backend": "nvidia",
            "group": "settings",
            "help": "Don't run extraction in parallel. Will run each part of the extraction "
                    "process separately (one after the other) rather than all at the smae time. "
                    "Useful if VRAM is at a premium."})
        argument_list.append({
            "opts": ("-s", "--skip-existing"),
            "action": "store_true",
            "dest": "skip_existing",
            "group": "settings",
            "default": False,
            "help": "Skips frames that have already been extracted and exist in the alignments "
                    "file"})
        argument_list.append({
            "opts": ("-sf", "--skip-existing-faces"),
            "action": "store_true",
            "dest": "skip_faces",
            "group": "settings",
            "default": False,
            "help": "Skip frames that already have detected faces in the alignments file"})
          return argument_list
  
  
  class ConvertArgs(ExtractConvertArgs):
      """ Class to parse the command line arguments for conversion.
keep keep keep keep replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace keep keep keep keep keep
 Smart Mask - Extract code review

- Lint simple_tests.py
- Only reformat alignments file if it exists otherwise change filename
- Update legacy alignments to new format at all stages
- faces_detect.Mask.from_dict - logging format fix
- convert.py fix otf for new pipeline
- cli.py - Add note that masks not used. Revert convert masks
- faces_detect.py - Revert non-extract code
- Add .p and .pickle extensions for serializer
- plugins/extract revert some changes
- scripts/fsmedia - Revert code changes
- Pipeline - cleanup
- Consistant alpha channel stripping (fixes single-process)
- Store landmarks as numpy array
- Code attribution
- Normalize feed face and reference face to 0.0 - 1.0 in convert
- Lock in mask VRAM sized
- Add documentation to plugin_loader
- Update alignments tool to work with new format 
lib/cli.py