                                                       resized_face,
                                                       filename)
          output_file = blurry_file if blurry_file else output_file
  
          if self.export_face:
              filename = "{}_{}{}".format(str(output_file),
                                          str(idx),
                                          Path(filename).suffix)
              Utils.cv2_read_write('write', filename, resized_face)
  
          return {"x": face.x,
                  "w": face.w,
                  "y": face.y,
                  "h": face.h,
                  "landmarksXY": face.landmarks_as_xy()}
 
</s> remove         blurry_file = self.faces.detect_blurry_faces(face,
                                                     t_mat,
                                                     resized_face,
                                                     filename)
        output_file = blurry_file if blurry_file else output_file
 </s> add             final_faces.append(face.to_alignment())
        self.alignments.data[os.path.basename(filename)] = final_faces </s> remove         self.extract.execute(self.media["image"],
                             manual_face=self.media["bounding_box"])
        landmarks = self.extract.landmarks[0][1]
        left, top, right, bottom = self.media["bounding_box"]
        alignment = {"x": left,
                     "w": right - left,
                     "y": top,
                     "h": bottom - top,
                     "landmarksXY": landmarks}
 </s> add         queue_manager.get_queue("in").put((self.media["image"],
                                           self.media["bounding_box"]))
        landmarks = queue_manager.get_queue("out").get()
        if landmarks == "EOF":
            exit(0)
        face = landmarks["detected_faces"][0]
        alignment = {"x": face.x,
                     "w": face.w,
                     "y": face.y,
                     "h": face.h,
                     "landmarksXY": face.landmarksXY} </s> remove         resized_face, t_mat = self.faces.extractor.extract(
            image,
            face,
            256,
            self.faces.align_eyes)
 </s> add         for idx, face in enumerate(faces["detected_faces"]):
            if self.export_face:
                save_queue.put((filename,
                                output_file,
                                resized_faces[idx],
                                idx)) </s> remove     def extract_multi_process(self):
        """ Run the extraction on the correct number of processes """
 </s> add         save_queue = queue_manager.get_queue("save")
        while True:
            item = save_queue.get()
            if item == "EOF":
                break
            filename, output_file, resized_face, idx = item
            out_filename = "{}_{}{}".format(str(output_file),
                                            str(idx),
                                            Path(filename).suffix)
            cv2.imwrite(out_filename, resized_face)

    def run_extraction(self, save_thread):
        """ Run Face Detection """
        to_process = self.process_item_count() </s> remove         self.faces.draw_landmarks_on_face(face, image)
 </s> add         filename = faces["filename"]
        output_file = faces["output_file"]
        resized_faces = faces["resized_faces"]
class Plugins():
    """ Detector and Aligner Plugins and queues """
    def __init__(self, arguments):
        self.args = arguments
        self.detector = self.load_detector()
        self.aligner = self.load_aligner()
        self.is_parallel = self.set_parallel_processing()

        self.add_queues()

    def set_parallel_processing(self):
        """ Set whether to run detect and align together or seperately """
        detector_vram = self.detector.vram
        aligner_vram = self.aligner.vram
        gpu_stats = GPUStats()
        if (detector_vram == 0
                or aligner_vram == 0
                or gpu_stats.device_count == 0):
            return True

        if hasattr(self.args, "multiprocess") and not self.args.multiprocess:
            print("\nNB: Parallel processing disabled.\nYou may get faster "
                  "extraction speeds by enabling it with the -mp switch\n")
            return False

        required_vram = detector_vram + aligner_vram + 320  # 320MB buffer
        stats = gpu_stats.get_card_most_free()
        free_vram = int(stats["free"])
        if self.args.verbose:
            print("{} - {}MB free of {}MB".format(stats["device"],
                                                  free_vram,
                                                  int(stats["total"])))
        if free_vram <= required_vram:
            if self.args.verbose:
                print("Not enough free VRAM for parallel processing. "
                      "Switching to serial")
            return False
        return True

    def add_queues(self):
        """ Add the required processing queues to Queue Manager """
        for task in ("load", "detect", "align", "save"):
            size = 0
            if task == "load" or (not self.is_parallel and task == "detect"):
                size = 100
            queue_manager.add_queue(task, maxsize=size)

    def load_detector(self):
        """ Set global arguments and load detector plugin """
        detector_name = self.args.detector.replace("-", "_").lower()

        # Rotation
        rotation = None
        if hasattr(self.args, "rotate_images"):
            rotation = self.args.rotate_images

        detector = PluginLoader.get_detector(detector_name)(
            verbose=self.args.verbose,
            rotation=rotation)

        return detector

    def load_aligner(self):
        """ Set global arguments and load aligner plugin """
        aligner_name = self.args.aligner.replace("-", "_").lower()

        # Align Eyes
        align_eyes = False
        if hasattr(self.args, 'align_eyes'):
            align_eyes = self.args.align_eyes

        # Extracted Face Size
        size = 256
        if hasattr(self.args, 'size'):
            size = self.args.size

        aligner = PluginLoader.get_aligner(aligner_name)(
            verbose=self.args.verbose,
            align_eyes=align_eyes,
            size=size)

        return aligner

    def launch_aligner(self):
        """ Launch the face aligner """
        out_queue = queue_manager.get_queue("align")
        kwargs = {"in_queue": queue_manager.get_queue("detect"),
                  "out_queue": out_queue}

        align_process = SpawnProcess()
        event = align_process.event

        align_process.in_process(self.aligner.align, **kwargs)

        # Wait for Aligner to take it's VRAM
        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Aligner")

    def launch_detector(self):
        """ Launch the face detector """
        out_queue = queue_manager.get_queue("detect")
        kwargs = {"in_queue": queue_manager.get_queue("load"),
                  "out_queue": out_queue}
        if self.args.detector == "mtcnn":
            mtcnn_kwargs = self.detector.validate_kwargs(
                self.get_mtcnn_kwargs())
            kwargs["mtcnn_kwargs"] = mtcnn_kwargs

        if self.detector.parent_is_pool:
            detect_process = PoolProcess(self.detector.detect_faces)
        else:
            detect_process = SpawnProcess()

        event = None
        if hasattr(detect_process, "event"):
            event = detect_process.event

        detect_process.in_process(self.detector.detect_faces, **kwargs)

        if not event:
            return

        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Detector")

    def get_mtcnn_kwargs(self):
        """ Add the mtcnn arguments into a kwargs dictionary """
        mtcnn_threshold = [float(thr.strip())
                           for thr in self.args.mtcnn_threshold]
        return {"minsize": self.args.mtcnn_minsize,
                "threshold": mtcnn_threshold,
                "factor": self.args.mtcnn_scalefactor}

    def detect_faces(self, extract_pass="detect"):
        """ Detect faces from in an image """
        if self.is_parallel or extract_pass == "align":
            out_queue = queue_manager.get_queue("align")
        if not self.is_parallel and extract_pass == "detect":
            out_queue = queue_manager.get_queue("detect")

        while True:
            try:
                faces = out_queue.get(True, 1)
                if faces == "EOF":
                    break
                exception = faces.get("exception", None)
                if exception is not None:
                    queue_manager.terminate_queues()
                    yield faces
                    break
            except QueueEmpty:
                continue

            yield faces
                                                       resized_face,
                                                       filename)
          output_file = blurry_file if blurry_file else output_file
  
class Plugins():
    """ Detector and Aligner Plugins and queues """
    def __init__(self, arguments):
        self.args = arguments
        self.detector = self.load_detector()
        self.aligner = self.load_aligner()
        self.is_parallel = self.set_parallel_processing()

        self.add_queues()

    def set_parallel_processing(self):
        """ Set whether to run detect and align together or seperately """
        detector_vram = self.detector.vram
        aligner_vram = self.aligner.vram
        gpu_stats = GPUStats()
        if (detector_vram == 0
                or aligner_vram == 0
                or gpu_stats.device_count == 0):
            return True

        if hasattr(self.args, "multiprocess") and not self.args.multiprocess:
            print("\nNB: Parallel processing disabled.\nYou may get faster "
                  "extraction speeds by enabling it with the -mp switch\n")
            return False

        required_vram = detector_vram + aligner_vram + 320  # 320MB buffer
        stats = gpu_stats.get_card_most_free()
        free_vram = int(stats["free"])
        if self.args.verbose:
            print("{} - {}MB free of {}MB".format(stats["device"],
                                                  free_vram,
                                                  int(stats["total"])))
        if free_vram <= required_vram:
            if self.args.verbose:
                print("Not enough free VRAM for parallel processing. "
                      "Switching to serial")
            return False
        return True

    def add_queues(self):
        """ Add the required processing queues to Queue Manager """
        for task in ("load", "detect", "align", "save"):
            size = 0
            if task == "load" or (not self.is_parallel and task == "detect"):
                size = 100
            queue_manager.add_queue(task, maxsize=size)

    def load_detector(self):
        """ Set global arguments and load detector plugin """
        detector_name = self.args.detector.replace("-", "_").lower()

        # Rotation
        rotation = None
        if hasattr(self.args, "rotate_images"):
            rotation = self.args.rotate_images

        detector = PluginLoader.get_detector(detector_name)(
            verbose=self.args.verbose,
            rotation=rotation)

        return detector

    def load_aligner(self):
        """ Set global arguments and load aligner plugin """
        aligner_name = self.args.aligner.replace("-", "_").lower()

        # Align Eyes
        align_eyes = False
        if hasattr(self.args, 'align_eyes'):
            align_eyes = self.args.align_eyes

        # Extracted Face Size
        size = 256
        if hasattr(self.args, 'size'):
            size = self.args.size

        aligner = PluginLoader.get_aligner(aligner_name)(
            verbose=self.args.verbose,
            align_eyes=align_eyes,
            size=size)

        return aligner

    def launch_aligner(self):
        """ Launch the face aligner """
        out_queue = queue_manager.get_queue("align")
        kwargs = {"in_queue": queue_manager.get_queue("detect"),
                  "out_queue": out_queue}

        align_process = SpawnProcess()
        event = align_process.event

        align_process.in_process(self.aligner.align, **kwargs)

        # Wait for Aligner to take it's VRAM
        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Aligner")

    def launch_detector(self):
        """ Launch the face detector """
        out_queue = queue_manager.get_queue("detect")
        kwargs = {"in_queue": queue_manager.get_queue("load"),
                  "out_queue": out_queue}
        if self.args.detector == "mtcnn":
            mtcnn_kwargs = self.detector.validate_kwargs(
                self.get_mtcnn_kwargs())
            kwargs["mtcnn_kwargs"] = mtcnn_kwargs

        if self.detector.parent_is_pool:
            detect_process = PoolProcess(self.detector.detect_faces)
        else:
            detect_process = SpawnProcess()

        event = None
        if hasattr(detect_process, "event"):
            event = detect_process.event

        detect_process.in_process(self.detector.detect_faces, **kwargs)

        if not event:
            return

        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Detector")

    def get_mtcnn_kwargs(self):
        """ Add the mtcnn arguments into a kwargs dictionary """
        mtcnn_threshold = [float(thr.strip())
                           for thr in self.args.mtcnn_threshold]
        return {"minsize": self.args.mtcnn_minsize,
                "threshold": mtcnn_threshold,
                "factor": self.args.mtcnn_scalefactor}

    def detect_faces(self, extract_pass="detect"):
        """ Detect faces from in an image """
        if self.is_parallel or extract_pass == "align":
            out_queue = queue_manager.get_queue("align")
        if not self.is_parallel and extract_pass == "detect":
            out_queue = queue_manager.get_queue("detect")

        while True:
            try:
                faces = out_queue.get(True, 1)
                if faces == "EOF":
                    break
                exception = faces.get("exception", None)
                if exception is not None:
                    queue_manager.terminate_queues()
                    yield faces
                    break
            except QueueEmpty:
                continue

            yield faces
class Plugins():
    """ Detector and Aligner Plugins and queues """
    def __init__(self, arguments):
        self.args = arguments
        self.detector = self.load_detector()
        self.aligner = self.load_aligner()
        self.is_parallel = self.set_parallel_processing()

        self.add_queues()

    def set_parallel_processing(self):
        """ Set whether to run detect and align together or seperately """
        detector_vram = self.detector.vram
        aligner_vram = self.aligner.vram
        gpu_stats = GPUStats()
        if (detector_vram == 0
                or aligner_vram == 0
                or gpu_stats.device_count == 0):
            return True

        if hasattr(self.args, "multiprocess") and not self.args.multiprocess:
            print("\nNB: Parallel processing disabled.\nYou may get faster "
                  "extraction speeds by enabling it with the -mp switch\n")
            return False

        required_vram = detector_vram + aligner_vram + 320  # 320MB buffer
        stats = gpu_stats.get_card_most_free()
        free_vram = int(stats["free"])
        if self.args.verbose:
            print("{} - {}MB free of {}MB".format(stats["device"],
                                                  free_vram,
                                                  int(stats["total"])))
        if free_vram <= required_vram:
            if self.args.verbose:
                print("Not enough free VRAM for parallel processing. "
                      "Switching to serial")
            return False
        return True

    def add_queues(self):
        """ Add the required processing queues to Queue Manager """
        for task in ("load", "detect", "align", "save"):
            size = 0
            if task == "load" or (not self.is_parallel and task == "detect"):
                size = 100
            queue_manager.add_queue(task, maxsize=size)

    def load_detector(self):
        """ Set global arguments and load detector plugin """
        detector_name = self.args.detector.replace("-", "_").lower()

        # Rotation
        rotation = None
        if hasattr(self.args, "rotate_images"):
            rotation = self.args.rotate_images

        detector = PluginLoader.get_detector(detector_name)(
            verbose=self.args.verbose,
            rotation=rotation)

        return detector

    def load_aligner(self):
        """ Set global arguments and load aligner plugin """
        aligner_name = self.args.aligner.replace("-", "_").lower()

        # Align Eyes
        align_eyes = False
        if hasattr(self.args, 'align_eyes'):
            align_eyes = self.args.align_eyes

        # Extracted Face Size
        size = 256
        if hasattr(self.args, 'size'):
            size = self.args.size

        aligner = PluginLoader.get_aligner(aligner_name)(
            verbose=self.args.verbose,
            align_eyes=align_eyes,
            size=size)

        return aligner

    def launch_aligner(self):
        """ Launch the face aligner """
        out_queue = queue_manager.get_queue("align")
        kwargs = {"in_queue": queue_manager.get_queue("detect"),
                  "out_queue": out_queue}

        align_process = SpawnProcess()
        event = align_process.event

        align_process.in_process(self.aligner.align, **kwargs)

        # Wait for Aligner to take it's VRAM
        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Aligner")

    def launch_detector(self):
        """ Launch the face detector """
        out_queue = queue_manager.get_queue("detect")
        kwargs = {"in_queue": queue_manager.get_queue("load"),
                  "out_queue": out_queue}
        if self.args.detector == "mtcnn":
            mtcnn_kwargs = self.detector.validate_kwargs(
                self.get_mtcnn_kwargs())
            kwargs["mtcnn_kwargs"] = mtcnn_kwargs

        if self.detector.parent_is_pool:
            detect_process = PoolProcess(self.detector.detect_faces)
        else:
            detect_process = SpawnProcess()

        event = None
        if hasattr(detect_process, "event"):
            event = detect_process.event

        detect_process.in_process(self.detector.detect_faces, **kwargs)

        if not event:
            return

        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Detector")

    def get_mtcnn_kwargs(self):
        """ Add the mtcnn arguments into a kwargs dictionary """
        mtcnn_threshold = [float(thr.strip())
                           for thr in self.args.mtcnn_threshold]
        return {"minsize": self.args.mtcnn_minsize,
                "threshold": mtcnn_threshold,
                "factor": self.args.mtcnn_scalefactor}

    def detect_faces(self, extract_pass="detect"):
        """ Detect faces from in an image """
        if self.is_parallel or extract_pass == "align":
            out_queue = queue_manager.get_queue("align")
        if not self.is_parallel and extract_pass == "detect":
            out_queue = queue_manager.get_queue("detect")

        while True:
            try:
                faces = out_queue.get(True, 1)
                if faces == "EOF":
                    break
                exception = faces.get("exception", None)
                if exception is not None:
                    queue_manager.terminate_queues()
                    yield faces
                    break
            except QueueEmpty:
                continue

            yield faces
class Plugins():
    """ Detector and Aligner Plugins and queues """
    def __init__(self, arguments):
        self.args = arguments
        self.detector = self.load_detector()
        self.aligner = self.load_aligner()
        self.is_parallel = self.set_parallel_processing()

        self.add_queues()

    def set_parallel_processing(self):
        """ Set whether to run detect and align together or seperately """
        detector_vram = self.detector.vram
        aligner_vram = self.aligner.vram
        gpu_stats = GPUStats()
        if (detector_vram == 0
                or aligner_vram == 0
                or gpu_stats.device_count == 0):
            return True

        if hasattr(self.args, "multiprocess") and not self.args.multiprocess:
            print("\nNB: Parallel processing disabled.\nYou may get faster "
                  "extraction speeds by enabling it with the -mp switch\n")
            return False

        required_vram = detector_vram + aligner_vram + 320  # 320MB buffer
        stats = gpu_stats.get_card_most_free()
        free_vram = int(stats["free"])
        if self.args.verbose:
            print("{} - {}MB free of {}MB".format(stats["device"],
                                                  free_vram,
                                                  int(stats["total"])))
        if free_vram <= required_vram:
            if self.args.verbose:
                print("Not enough free VRAM for parallel processing. "
                      "Switching to serial")
            return False
        return True

    def add_queues(self):
        """ Add the required processing queues to Queue Manager """
        for task in ("load", "detect", "align", "save"):
            size = 0
            if task == "load" or (not self.is_parallel and task == "detect"):
                size = 100
            queue_manager.add_queue(task, maxsize=size)

    def load_detector(self):
        """ Set global arguments and load detector plugin """
        detector_name = self.args.detector.replace("-", "_").lower()

        # Rotation
        rotation = None
        if hasattr(self.args, "rotate_images"):
            rotation = self.args.rotate_images

        detector = PluginLoader.get_detector(detector_name)(
            verbose=self.args.verbose,
            rotation=rotation)

        return detector

    def load_aligner(self):
        """ Set global arguments and load aligner plugin """
        aligner_name = self.args.aligner.replace("-", "_").lower()

        # Align Eyes
        align_eyes = False
        if hasattr(self.args, 'align_eyes'):
            align_eyes = self.args.align_eyes

        # Extracted Face Size
        size = 256
        if hasattr(self.args, 'size'):
            size = self.args.size

        aligner = PluginLoader.get_aligner(aligner_name)(
            verbose=self.args.verbose,
            align_eyes=align_eyes,
            size=size)

        return aligner

    def launch_aligner(self):
        """ Launch the face aligner """
        out_queue = queue_manager.get_queue("align")
        kwargs = {"in_queue": queue_manager.get_queue("detect"),
                  "out_queue": out_queue}

        align_process = SpawnProcess()
        event = align_process.event

        align_process.in_process(self.aligner.align, **kwargs)

        # Wait for Aligner to take it's VRAM
        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Aligner")

    def launch_detector(self):
        """ Launch the face detector """
        out_queue = queue_manager.get_queue("detect")
        kwargs = {"in_queue": queue_manager.get_queue("load"),
                  "out_queue": out_queue}
        if self.args.detector == "mtcnn":
            mtcnn_kwargs = self.detector.validate_kwargs(
                self.get_mtcnn_kwargs())
            kwargs["mtcnn_kwargs"] = mtcnn_kwargs

        if self.detector.parent_is_pool:
            detect_process = PoolProcess(self.detector.detect_faces)
        else:
            detect_process = SpawnProcess()

        event = None
        if hasattr(detect_process, "event"):
            event = detect_process.event

        detect_process.in_process(self.detector.detect_faces, **kwargs)

        if not event:
            return

        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Detector")

    def get_mtcnn_kwargs(self):
        """ Add the mtcnn arguments into a kwargs dictionary """
        mtcnn_threshold = [float(thr.strip())
                           for thr in self.args.mtcnn_threshold]
        return {"minsize": self.args.mtcnn_minsize,
                "threshold": mtcnn_threshold,
                "factor": self.args.mtcnn_scalefactor}

    def detect_faces(self, extract_pass="detect"):
        """ Detect faces from in an image """
        if self.is_parallel or extract_pass == "align":
            out_queue = queue_manager.get_queue("align")
        if not self.is_parallel and extract_pass == "detect":
            out_queue = queue_manager.get_queue("detect")

        while True:
            try:
                faces = out_queue.get(True, 1)
                if faces == "EOF":
                    break
                exception = faces.get("exception", None)
                if exception is not None:
                    queue_manager.terminate_queues()
                    yield faces
                    break
            except QueueEmpty:
                continue

            yield faces
class Plugins():
    """ Detector and Aligner Plugins and queues """
    def __init__(self, arguments):
        self.args = arguments
        self.detector = self.load_detector()
        self.aligner = self.load_aligner()
        self.is_parallel = self.set_parallel_processing()

        self.add_queues()

    def set_parallel_processing(self):
        """ Set whether to run detect and align together or seperately """
        detector_vram = self.detector.vram
        aligner_vram = self.aligner.vram
        gpu_stats = GPUStats()
        if (detector_vram == 0
                or aligner_vram == 0
                or gpu_stats.device_count == 0):
            return True

        if hasattr(self.args, "multiprocess") and not self.args.multiprocess:
            print("\nNB: Parallel processing disabled.\nYou may get faster "
                  "extraction speeds by enabling it with the -mp switch\n")
            return False

        required_vram = detector_vram + aligner_vram + 320  # 320MB buffer
        stats = gpu_stats.get_card_most_free()
        free_vram = int(stats["free"])
        if self.args.verbose:
            print("{} - {}MB free of {}MB".format(stats["device"],
                                                  free_vram,
                                                  int(stats["total"])))
        if free_vram <= required_vram:
            if self.args.verbose:
                print("Not enough free VRAM for parallel processing. "
                      "Switching to serial")
            return False
        return True

    def add_queues(self):
        """ Add the required processing queues to Queue Manager """
        for task in ("load", "detect", "align", "save"):
            size = 0
            if task == "load" or (not self.is_parallel and task == "detect"):
                size = 100
            queue_manager.add_queue(task, maxsize=size)

    def load_detector(self):
        """ Set global arguments and load detector plugin """
        detector_name = self.args.detector.replace("-", "_").lower()

        # Rotation
        rotation = None
        if hasattr(self.args, "rotate_images"):
            rotation = self.args.rotate_images

        detector = PluginLoader.get_detector(detector_name)(
            verbose=self.args.verbose,
            rotation=rotation)

        return detector

    def load_aligner(self):
        """ Set global arguments and load aligner plugin """
        aligner_name = self.args.aligner.replace("-", "_").lower()

        # Align Eyes
        align_eyes = False
        if hasattr(self.args, 'align_eyes'):
            align_eyes = self.args.align_eyes

        # Extracted Face Size
        size = 256
        if hasattr(self.args, 'size'):
            size = self.args.size

        aligner = PluginLoader.get_aligner(aligner_name)(
            verbose=self.args.verbose,
            align_eyes=align_eyes,
            size=size)

        return aligner

    def launch_aligner(self):
        """ Launch the face aligner """
        out_queue = queue_manager.get_queue("align")
        kwargs = {"in_queue": queue_manager.get_queue("detect"),
                  "out_queue": out_queue}

        align_process = SpawnProcess()
        event = align_process.event

        align_process.in_process(self.aligner.align, **kwargs)

        # Wait for Aligner to take it's VRAM
        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Aligner")

    def launch_detector(self):
        """ Launch the face detector """
        out_queue = queue_manager.get_queue("detect")
        kwargs = {"in_queue": queue_manager.get_queue("load"),
                  "out_queue": out_queue}
        if self.args.detector == "mtcnn":
            mtcnn_kwargs = self.detector.validate_kwargs(
                self.get_mtcnn_kwargs())
            kwargs["mtcnn_kwargs"] = mtcnn_kwargs

        if self.detector.parent_is_pool:
            detect_process = PoolProcess(self.detector.detect_faces)
        else:
            detect_process = SpawnProcess()

        event = None
        if hasattr(detect_process, "event"):
            event = detect_process.event

        detect_process.in_process(self.detector.detect_faces, **kwargs)

        if not event:
            return

        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Detector")

    def get_mtcnn_kwargs(self):
        """ Add the mtcnn arguments into a kwargs dictionary """
        mtcnn_threshold = [float(thr.strip())
                           for thr in self.args.mtcnn_threshold]
        return {"minsize": self.args.mtcnn_minsize,
                "threshold": mtcnn_threshold,
                "factor": self.args.mtcnn_scalefactor}

    def detect_faces(self, extract_pass="detect"):
        """ Detect faces from in an image """
        if self.is_parallel or extract_pass == "align":
            out_queue = queue_manager.get_queue("align")
        if not self.is_parallel and extract_pass == "detect":
            out_queue = queue_manager.get_queue("detect")

        while True:
            try:
                faces = out_queue.get(True, 1)
                if faces == "EOF":
                    break
                exception = faces.get("exception", None)
                if exception is not None:
                    queue_manager.terminate_queues()
                    yield faces
                    break
            except QueueEmpty:
                continue

            yield faces
class Plugins():
    """ Detector and Aligner Plugins and queues """
    def __init__(self, arguments):
        self.args = arguments
        self.detector = self.load_detector()
        self.aligner = self.load_aligner()
        self.is_parallel = self.set_parallel_processing()

        self.add_queues()

    def set_parallel_processing(self):
        """ Set whether to run detect and align together or seperately """
        detector_vram = self.detector.vram
        aligner_vram = self.aligner.vram
        gpu_stats = GPUStats()
        if (detector_vram == 0
                or aligner_vram == 0
                or gpu_stats.device_count == 0):
            return True

        if hasattr(self.args, "multiprocess") and not self.args.multiprocess:
            print("\nNB: Parallel processing disabled.\nYou may get faster "
                  "extraction speeds by enabling it with the -mp switch\n")
            return False

        required_vram = detector_vram + aligner_vram + 320  # 320MB buffer
        stats = gpu_stats.get_card_most_free()
        free_vram = int(stats["free"])
        if self.args.verbose:
            print("{} - {}MB free of {}MB".format(stats["device"],
                                                  free_vram,
                                                  int(stats["total"])))
        if free_vram <= required_vram:
            if self.args.verbose:
                print("Not enough free VRAM for parallel processing. "
                      "Switching to serial")
            return False
        return True

    def add_queues(self):
        """ Add the required processing queues to Queue Manager """
        for task in ("load", "detect", "align", "save"):
            size = 0
            if task == "load" or (not self.is_parallel and task == "detect"):
                size = 100
            queue_manager.add_queue(task, maxsize=size)

    def load_detector(self):
        """ Set global arguments and load detector plugin """
        detector_name = self.args.detector.replace("-", "_").lower()

        # Rotation
        rotation = None
        if hasattr(self.args, "rotate_images"):
            rotation = self.args.rotate_images

        detector = PluginLoader.get_detector(detector_name)(
            verbose=self.args.verbose,
            rotation=rotation)

        return detector

    def load_aligner(self):
        """ Set global arguments and load aligner plugin """
        aligner_name = self.args.aligner.replace("-", "_").lower()

        # Align Eyes
        align_eyes = False
        if hasattr(self.args, 'align_eyes'):
            align_eyes = self.args.align_eyes

        # Extracted Face Size
        size = 256
        if hasattr(self.args, 'size'):
            size = self.args.size

        aligner = PluginLoader.get_aligner(aligner_name)(
            verbose=self.args.verbose,
            align_eyes=align_eyes,
            size=size)

        return aligner

    def launch_aligner(self):
        """ Launch the face aligner """
        out_queue = queue_manager.get_queue("align")
        kwargs = {"in_queue": queue_manager.get_queue("detect"),
                  "out_queue": out_queue}

        align_process = SpawnProcess()
        event = align_process.event

        align_process.in_process(self.aligner.align, **kwargs)

        # Wait for Aligner to take it's VRAM
        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Aligner")

    def launch_detector(self):
        """ Launch the face detector """
        out_queue = queue_manager.get_queue("detect")
        kwargs = {"in_queue": queue_manager.get_queue("load"),
                  "out_queue": out_queue}
        if self.args.detector == "mtcnn":
            mtcnn_kwargs = self.detector.validate_kwargs(
                self.get_mtcnn_kwargs())
            kwargs["mtcnn_kwargs"] = mtcnn_kwargs

        if self.detector.parent_is_pool:
            detect_process = PoolProcess(self.detector.detect_faces)
        else:
            detect_process = SpawnProcess()

        event = None
        if hasattr(detect_process, "event"):
            event = detect_process.event

        detect_process.in_process(self.detector.detect_faces, **kwargs)

        if not event:
            return

        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Detector")

    def get_mtcnn_kwargs(self):
        """ Add the mtcnn arguments into a kwargs dictionary """
        mtcnn_threshold = [float(thr.strip())
                           for thr in self.args.mtcnn_threshold]
        return {"minsize": self.args.mtcnn_minsize,
                "threshold": mtcnn_threshold,
                "factor": self.args.mtcnn_scalefactor}

    def detect_faces(self, extract_pass="detect"):
        """ Detect faces from in an image """
        if self.is_parallel or extract_pass == "align":
            out_queue = queue_manager.get_queue("align")
        if not self.is_parallel and extract_pass == "detect":
            out_queue = queue_manager.get_queue("detect")

        while True:
            try:
                faces = out_queue.get(True, 1)
                if faces == "EOF":
                    break
                exception = faces.get("exception", None)
                if exception is not None:
                    queue_manager.terminate_queues()
                    yield faces
                    break
            except QueueEmpty:
                continue

            yield faces
class Plugins():
    """ Detector and Aligner Plugins and queues """
    def __init__(self, arguments):
        self.args = arguments
        self.detector = self.load_detector()
        self.aligner = self.load_aligner()
        self.is_parallel = self.set_parallel_processing()

        self.add_queues()

    def set_parallel_processing(self):
        """ Set whether to run detect and align together or seperately """
        detector_vram = self.detector.vram
        aligner_vram = self.aligner.vram
        gpu_stats = GPUStats()
        if (detector_vram == 0
                or aligner_vram == 0
                or gpu_stats.device_count == 0):
            return True

        if hasattr(self.args, "multiprocess") and not self.args.multiprocess:
            print("\nNB: Parallel processing disabled.\nYou may get faster "
                  "extraction speeds by enabling it with the -mp switch\n")
            return False

        required_vram = detector_vram + aligner_vram + 320  # 320MB buffer
        stats = gpu_stats.get_card_most_free()
        free_vram = int(stats["free"])
        if self.args.verbose:
            print("{} - {}MB free of {}MB".format(stats["device"],
                                                  free_vram,
                                                  int(stats["total"])))
        if free_vram <= required_vram:
            if self.args.verbose:
                print("Not enough free VRAM for parallel processing. "
                      "Switching to serial")
            return False
        return True

    def add_queues(self):
        """ Add the required processing queues to Queue Manager """
        for task in ("load", "detect", "align", "save"):
            size = 0
            if task == "load" or (not self.is_parallel and task == "detect"):
                size = 100
            queue_manager.add_queue(task, maxsize=size)

    def load_detector(self):
        """ Set global arguments and load detector plugin """
        detector_name = self.args.detector.replace("-", "_").lower()

        # Rotation
        rotation = None
        if hasattr(self.args, "rotate_images"):
            rotation = self.args.rotate_images

        detector = PluginLoader.get_detector(detector_name)(
            verbose=self.args.verbose,
            rotation=rotation)

        return detector

    def load_aligner(self):
        """ Set global arguments and load aligner plugin """
        aligner_name = self.args.aligner.replace("-", "_").lower()

        # Align Eyes
        align_eyes = False
        if hasattr(self.args, 'align_eyes'):
            align_eyes = self.args.align_eyes

        # Extracted Face Size
        size = 256
        if hasattr(self.args, 'size'):
            size = self.args.size

        aligner = PluginLoader.get_aligner(aligner_name)(
            verbose=self.args.verbose,
            align_eyes=align_eyes,
            size=size)

        return aligner

    def launch_aligner(self):
        """ Launch the face aligner """
        out_queue = queue_manager.get_queue("align")
        kwargs = {"in_queue": queue_manager.get_queue("detect"),
                  "out_queue": out_queue}

        align_process = SpawnProcess()
        event = align_process.event

        align_process.in_process(self.aligner.align, **kwargs)

        # Wait for Aligner to take it's VRAM
        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Aligner")

    def launch_detector(self):
        """ Launch the face detector """
        out_queue = queue_manager.get_queue("detect")
        kwargs = {"in_queue": queue_manager.get_queue("load"),
                  "out_queue": out_queue}
        if self.args.detector == "mtcnn":
            mtcnn_kwargs = self.detector.validate_kwargs(
                self.get_mtcnn_kwargs())
            kwargs["mtcnn_kwargs"] = mtcnn_kwargs

        if self.detector.parent_is_pool:
            detect_process = PoolProcess(self.detector.detect_faces)
        else:
            detect_process = SpawnProcess()

        event = None
        if hasattr(detect_process, "event"):
            event = detect_process.event

        detect_process.in_process(self.detector.detect_faces, **kwargs)

        if not event:
            return

        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Detector")

    def get_mtcnn_kwargs(self):
        """ Add the mtcnn arguments into a kwargs dictionary """
        mtcnn_threshold = [float(thr.strip())
                           for thr in self.args.mtcnn_threshold]
        return {"minsize": self.args.mtcnn_minsize,
                "threshold": mtcnn_threshold,
                "factor": self.args.mtcnn_scalefactor}

    def detect_faces(self, extract_pass="detect"):
        """ Detect faces from in an image """
        if self.is_parallel or extract_pass == "align":
            out_queue = queue_manager.get_queue("align")
        if not self.is_parallel and extract_pass == "detect":
            out_queue = queue_manager.get_queue("detect")

        while True:
            try:
                faces = out_queue.get(True, 1)
                if faces == "EOF":
                    break
                exception = faces.get("exception", None)
                if exception is not None:
                    queue_manager.terminate_queues()
                    yield faces
                    break
            except QueueEmpty:
                continue

            yield faces
class Plugins():
    """ Detector and Aligner Plugins and queues """
    def __init__(self, arguments):
        self.args = arguments
        self.detector = self.load_detector()
        self.aligner = self.load_aligner()
        self.is_parallel = self.set_parallel_processing()

        self.add_queues()

    def set_parallel_processing(self):
        """ Set whether to run detect and align together or seperately """
        detector_vram = self.detector.vram
        aligner_vram = self.aligner.vram
        gpu_stats = GPUStats()
        if (detector_vram == 0
                or aligner_vram == 0
                or gpu_stats.device_count == 0):
            return True

        if hasattr(self.args, "multiprocess") and not self.args.multiprocess:
            print("\nNB: Parallel processing disabled.\nYou may get faster "
                  "extraction speeds by enabling it with the -mp switch\n")
            return False

        required_vram = detector_vram + aligner_vram + 320  # 320MB buffer
        stats = gpu_stats.get_card_most_free()
        free_vram = int(stats["free"])
        if self.args.verbose:
            print("{} - {}MB free of {}MB".format(stats["device"],
                                                  free_vram,
                                                  int(stats["total"])))
        if free_vram <= required_vram:
            if self.args.verbose:
                print("Not enough free VRAM for parallel processing. "
                      "Switching to serial")
            return False
        return True

    def add_queues(self):
        """ Add the required processing queues to Queue Manager """
        for task in ("load", "detect", "align", "save"):
            size = 0
            if task == "load" or (not self.is_parallel and task == "detect"):
                size = 100
            queue_manager.add_queue(task, maxsize=size)

    def load_detector(self):
        """ Set global arguments and load detector plugin """
        detector_name = self.args.detector.replace("-", "_").lower()

        # Rotation
        rotation = None
        if hasattr(self.args, "rotate_images"):
            rotation = self.args.rotate_images

        detector = PluginLoader.get_detector(detector_name)(
            verbose=self.args.verbose,
            rotation=rotation)

        return detector

    def load_aligner(self):
        """ Set global arguments and load aligner plugin """
        aligner_name = self.args.aligner.replace("-", "_").lower()

        # Align Eyes
        align_eyes = False
        if hasattr(self.args, 'align_eyes'):
            align_eyes = self.args.align_eyes

        # Extracted Face Size
        size = 256
        if hasattr(self.args, 'size'):
            size = self.args.size

        aligner = PluginLoader.get_aligner(aligner_name)(
            verbose=self.args.verbose,
            align_eyes=align_eyes,
            size=size)

        return aligner

    def launch_aligner(self):
        """ Launch the face aligner """
        out_queue = queue_manager.get_queue("align")
        kwargs = {"in_queue": queue_manager.get_queue("detect"),
                  "out_queue": out_queue}

        align_process = SpawnProcess()
        event = align_process.event

        align_process.in_process(self.aligner.align, **kwargs)

        # Wait for Aligner to take it's VRAM
        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Aligner")

    def launch_detector(self):
        """ Launch the face detector """
        out_queue = queue_manager.get_queue("detect")
        kwargs = {"in_queue": queue_manager.get_queue("load"),
                  "out_queue": out_queue}
        if self.args.detector == "mtcnn":
            mtcnn_kwargs = self.detector.validate_kwargs(
                self.get_mtcnn_kwargs())
            kwargs["mtcnn_kwargs"] = mtcnn_kwargs

        if self.detector.parent_is_pool:
            detect_process = PoolProcess(self.detector.detect_faces)
        else:
            detect_process = SpawnProcess()

        event = None
        if hasattr(detect_process, "event"):
            event = detect_process.event

        detect_process.in_process(self.detector.detect_faces, **kwargs)

        if not event:
            return

        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Detector")

    def get_mtcnn_kwargs(self):
        """ Add the mtcnn arguments into a kwargs dictionary """
        mtcnn_threshold = [float(thr.strip())
                           for thr in self.args.mtcnn_threshold]
        return {"minsize": self.args.mtcnn_minsize,
                "threshold": mtcnn_threshold,
                "factor": self.args.mtcnn_scalefactor}

    def detect_faces(self, extract_pass="detect"):
        """ Detect faces from in an image """
        if self.is_parallel or extract_pass == "align":
            out_queue = queue_manager.get_queue("align")
        if not self.is_parallel and extract_pass == "detect":
            out_queue = queue_manager.get_queue("detect")

        while True:
            try:
                faces = out_queue.get(True, 1)
                if faces == "EOF":
                    break
                exception = faces.get("exception", None)
                if exception is not None:
                    queue_manager.terminate_queues()
                    yield faces
                    break
            except QueueEmpty:
                continue

            yield faces
class Plugins():
    """ Detector and Aligner Plugins and queues """
    def __init__(self, arguments):
        self.args = arguments
        self.detector = self.load_detector()
        self.aligner = self.load_aligner()
        self.is_parallel = self.set_parallel_processing()

        self.add_queues()

    def set_parallel_processing(self):
        """ Set whether to run detect and align together or seperately """
        detector_vram = self.detector.vram
        aligner_vram = self.aligner.vram
        gpu_stats = GPUStats()
        if (detector_vram == 0
                or aligner_vram == 0
                or gpu_stats.device_count == 0):
            return True

        if hasattr(self.args, "multiprocess") and not self.args.multiprocess:
            print("\nNB: Parallel processing disabled.\nYou may get faster "
                  "extraction speeds by enabling it with the -mp switch\n")
            return False

        required_vram = detector_vram + aligner_vram + 320  # 320MB buffer
        stats = gpu_stats.get_card_most_free()
        free_vram = int(stats["free"])
        if self.args.verbose:
            print("{} - {}MB free of {}MB".format(stats["device"],
                                                  free_vram,
                                                  int(stats["total"])))
        if free_vram <= required_vram:
            if self.args.verbose:
                print("Not enough free VRAM for parallel processing. "
                      "Switching to serial")
            return False
        return True

    def add_queues(self):
        """ Add the required processing queues to Queue Manager """
        for task in ("load", "detect", "align", "save"):
            size = 0
            if task == "load" or (not self.is_parallel and task == "detect"):
                size = 100
            queue_manager.add_queue(task, maxsize=size)

    def load_detector(self):
        """ Set global arguments and load detector plugin """
        detector_name = self.args.detector.replace("-", "_").lower()

        # Rotation
        rotation = None
        if hasattr(self.args, "rotate_images"):
            rotation = self.args.rotate_images

        detector = PluginLoader.get_detector(detector_name)(
            verbose=self.args.verbose,
            rotation=rotation)

        return detector

    def load_aligner(self):
        """ Set global arguments and load aligner plugin """
        aligner_name = self.args.aligner.replace("-", "_").lower()

        # Align Eyes
        align_eyes = False
        if hasattr(self.args, 'align_eyes'):
            align_eyes = self.args.align_eyes

        # Extracted Face Size
        size = 256
        if hasattr(self.args, 'size'):
            size = self.args.size

        aligner = PluginLoader.get_aligner(aligner_name)(
            verbose=self.args.verbose,
            align_eyes=align_eyes,
            size=size)

        return aligner

    def launch_aligner(self):
        """ Launch the face aligner """
        out_queue = queue_manager.get_queue("align")
        kwargs = {"in_queue": queue_manager.get_queue("detect"),
                  "out_queue": out_queue}

        align_process = SpawnProcess()
        event = align_process.event

        align_process.in_process(self.aligner.align, **kwargs)

        # Wait for Aligner to take it's VRAM
        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Aligner")

    def launch_detector(self):
        """ Launch the face detector """
        out_queue = queue_manager.get_queue("detect")
        kwargs = {"in_queue": queue_manager.get_queue("load"),
                  "out_queue": out_queue}
        if self.args.detector == "mtcnn":
            mtcnn_kwargs = self.detector.validate_kwargs(
                self.get_mtcnn_kwargs())
            kwargs["mtcnn_kwargs"] = mtcnn_kwargs

        if self.detector.parent_is_pool:
            detect_process = PoolProcess(self.detector.detect_faces)
        else:
            detect_process = SpawnProcess()

        event = None
        if hasattr(detect_process, "event"):
            event = detect_process.event

        detect_process.in_process(self.detector.detect_faces, **kwargs)

        if not event:
            return

        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Detector")

    def get_mtcnn_kwargs(self):
        """ Add the mtcnn arguments into a kwargs dictionary """
        mtcnn_threshold = [float(thr.strip())
                           for thr in self.args.mtcnn_threshold]
        return {"minsize": self.args.mtcnn_minsize,
                "threshold": mtcnn_threshold,
                "factor": self.args.mtcnn_scalefactor}

    def detect_faces(self, extract_pass="detect"):
        """ Detect faces from in an image """
        if self.is_parallel or extract_pass == "align":
            out_queue = queue_manager.get_queue("align")
        if not self.is_parallel and extract_pass == "detect":
            out_queue = queue_manager.get_queue("detect")

        while True:
            try:
                faces = out_queue.get(True, 1)
                if faces == "EOF":
                    break
                exception = faces.get("exception", None)
                if exception is not None:
                    queue_manager.terminate_queues()
                    yield faces
                    break
            except QueueEmpty:
                continue

            yield faces
class Plugins():
    """ Detector and Aligner Plugins and queues """
    def __init__(self, arguments):
        self.args = arguments
        self.detector = self.load_detector()
        self.aligner = self.load_aligner()
        self.is_parallel = self.set_parallel_processing()

        self.add_queues()

    def set_parallel_processing(self):
        """ Set whether to run detect and align together or seperately """
        detector_vram = self.detector.vram
        aligner_vram = self.aligner.vram
        gpu_stats = GPUStats()
        if (detector_vram == 0
                or aligner_vram == 0
                or gpu_stats.device_count == 0):
            return True

        if hasattr(self.args, "multiprocess") and not self.args.multiprocess:
            print("\nNB: Parallel processing disabled.\nYou may get faster "
                  "extraction speeds by enabling it with the -mp switch\n")
            return False

        required_vram = detector_vram + aligner_vram + 320  # 320MB buffer
        stats = gpu_stats.get_card_most_free()
        free_vram = int(stats["free"])
        if self.args.verbose:
            print("{} - {}MB free of {}MB".format(stats["device"],
                                                  free_vram,
                                                  int(stats["total"])))
        if free_vram <= required_vram:
            if self.args.verbose:
                print("Not enough free VRAM for parallel processing. "
                      "Switching to serial")
            return False
        return True

    def add_queues(self):
        """ Add the required processing queues to Queue Manager """
        for task in ("load", "detect", "align", "save"):
            size = 0
            if task == "load" or (not self.is_parallel and task == "detect"):
                size = 100
            queue_manager.add_queue(task, maxsize=size)

    def load_detector(self):
        """ Set global arguments and load detector plugin """
        detector_name = self.args.detector.replace("-", "_").lower()

        # Rotation
        rotation = None
        if hasattr(self.args, "rotate_images"):
            rotation = self.args.rotate_images

        detector = PluginLoader.get_detector(detector_name)(
            verbose=self.args.verbose,
            rotation=rotation)

        return detector

    def load_aligner(self):
        """ Set global arguments and load aligner plugin """
        aligner_name = self.args.aligner.replace("-", "_").lower()

        # Align Eyes
        align_eyes = False
        if hasattr(self.args, 'align_eyes'):
            align_eyes = self.args.align_eyes

        # Extracted Face Size
        size = 256
        if hasattr(self.args, 'size'):
            size = self.args.size

        aligner = PluginLoader.get_aligner(aligner_name)(
            verbose=self.args.verbose,
            align_eyes=align_eyes,
            size=size)

        return aligner

    def launch_aligner(self):
        """ Launch the face aligner """
        out_queue = queue_manager.get_queue("align")
        kwargs = {"in_queue": queue_manager.get_queue("detect"),
                  "out_queue": out_queue}

        align_process = SpawnProcess()
        event = align_process.event

        align_process.in_process(self.aligner.align, **kwargs)

        # Wait for Aligner to take it's VRAM
        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Aligner")

    def launch_detector(self):
        """ Launch the face detector """
        out_queue = queue_manager.get_queue("detect")
        kwargs = {"in_queue": queue_manager.get_queue("load"),
                  "out_queue": out_queue}
        if self.args.detector == "mtcnn":
            mtcnn_kwargs = self.detector.validate_kwargs(
                self.get_mtcnn_kwargs())
            kwargs["mtcnn_kwargs"] = mtcnn_kwargs

        if self.detector.parent_is_pool:
            detect_process = PoolProcess(self.detector.detect_faces)
        else:
            detect_process = SpawnProcess()

        event = None
        if hasattr(detect_process, "event"):
            event = detect_process.event

        detect_process.in_process(self.detector.detect_faces, **kwargs)

        if not event:
            return

        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Detector")

    def get_mtcnn_kwargs(self):
        """ Add the mtcnn arguments into a kwargs dictionary """
        mtcnn_threshold = [float(thr.strip())
                           for thr in self.args.mtcnn_threshold]
        return {"minsize": self.args.mtcnn_minsize,
                "threshold": mtcnn_threshold,
                "factor": self.args.mtcnn_scalefactor}

    def detect_faces(self, extract_pass="detect"):
        """ Detect faces from in an image """
        if self.is_parallel or extract_pass == "align":
            out_queue = queue_manager.get_queue("align")
        if not self.is_parallel and extract_pass == "detect":
            out_queue = queue_manager.get_queue("detect")

        while True:
            try:
                faces = out_queue.get(True, 1)
                if faces == "EOF":
                    break
                exception = faces.get("exception", None)
                if exception is not None:
                    queue_manager.terminate_queues()
                    yield faces
                    break
            except QueueEmpty:
                continue

            yield faces
class Plugins():
    """ Detector and Aligner Plugins and queues """
    def __init__(self, arguments):
        self.args = arguments
        self.detector = self.load_detector()
        self.aligner = self.load_aligner()
        self.is_parallel = self.set_parallel_processing()

        self.add_queues()

    def set_parallel_processing(self):
        """ Set whether to run detect and align together or seperately """
        detector_vram = self.detector.vram
        aligner_vram = self.aligner.vram
        gpu_stats = GPUStats()
        if (detector_vram == 0
                or aligner_vram == 0
                or gpu_stats.device_count == 0):
            return True

        if hasattr(self.args, "multiprocess") and not self.args.multiprocess:
            print("\nNB: Parallel processing disabled.\nYou may get faster "
                  "extraction speeds by enabling it with the -mp switch\n")
            return False

        required_vram = detector_vram + aligner_vram + 320  # 320MB buffer
        stats = gpu_stats.get_card_most_free()
        free_vram = int(stats["free"])
        if self.args.verbose:
            print("{} - {}MB free of {}MB".format(stats["device"],
                                                  free_vram,
                                                  int(stats["total"])))
        if free_vram <= required_vram:
            if self.args.verbose:
                print("Not enough free VRAM for parallel processing. "
                      "Switching to serial")
            return False
        return True

    def add_queues(self):
        """ Add the required processing queues to Queue Manager """
        for task in ("load", "detect", "align", "save"):
            size = 0
            if task == "load" or (not self.is_parallel and task == "detect"):
                size = 100
            queue_manager.add_queue(task, maxsize=size)

    def load_detector(self):
        """ Set global arguments and load detector plugin """
        detector_name = self.args.detector.replace("-", "_").lower()

        # Rotation
        rotation = None
        if hasattr(self.args, "rotate_images"):
            rotation = self.args.rotate_images

        detector = PluginLoader.get_detector(detector_name)(
            verbose=self.args.verbose,
            rotation=rotation)

        return detector

    def load_aligner(self):
        """ Set global arguments and load aligner plugin """
        aligner_name = self.args.aligner.replace("-", "_").lower()

        # Align Eyes
        align_eyes = False
        if hasattr(self.args, 'align_eyes'):
            align_eyes = self.args.align_eyes

        # Extracted Face Size
        size = 256
        if hasattr(self.args, 'size'):
            size = self.args.size

        aligner = PluginLoader.get_aligner(aligner_name)(
            verbose=self.args.verbose,
            align_eyes=align_eyes,
            size=size)

        return aligner

    def launch_aligner(self):
        """ Launch the face aligner """
        out_queue = queue_manager.get_queue("align")
        kwargs = {"in_queue": queue_manager.get_queue("detect"),
                  "out_queue": out_queue}

        align_process = SpawnProcess()
        event = align_process.event

        align_process.in_process(self.aligner.align, **kwargs)

        # Wait for Aligner to take it's VRAM
        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Aligner")

    def launch_detector(self):
        """ Launch the face detector """
        out_queue = queue_manager.get_queue("detect")
        kwargs = {"in_queue": queue_manager.get_queue("load"),
                  "out_queue": out_queue}
        if self.args.detector == "mtcnn":
            mtcnn_kwargs = self.detector.validate_kwargs(
                self.get_mtcnn_kwargs())
            kwargs["mtcnn_kwargs"] = mtcnn_kwargs

        if self.detector.parent_is_pool:
            detect_process = PoolProcess(self.detector.detect_faces)
        else:
            detect_process = SpawnProcess()

        event = None
        if hasattr(detect_process, "event"):
            event = detect_process.event

        detect_process.in_process(self.detector.detect_faces, **kwargs)

        if not event:
            return

        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Detector")

    def get_mtcnn_kwargs(self):
        """ Add the mtcnn arguments into a kwargs dictionary """
        mtcnn_threshold = [float(thr.strip())
                           for thr in self.args.mtcnn_threshold]
        return {"minsize": self.args.mtcnn_minsize,
                "threshold": mtcnn_threshold,
                "factor": self.args.mtcnn_scalefactor}

    def detect_faces(self, extract_pass="detect"):
        """ Detect faces from in an image """
        if self.is_parallel or extract_pass == "align":
            out_queue = queue_manager.get_queue("align")
        if not self.is_parallel and extract_pass == "detect":
            out_queue = queue_manager.get_queue("detect")

        while True:
            try:
                faces = out_queue.get(True, 1)
                if faces == "EOF":
                    break
                exception = faces.get("exception", None)
                if exception is not None:
                    queue_manager.terminate_queues()
                    yield faces
                    break
            except QueueEmpty:
                continue

            yield faces
class Plugins():
    """ Detector and Aligner Plugins and queues """
    def __init__(self, arguments):
        self.args = arguments
        self.detector = self.load_detector()
        self.aligner = self.load_aligner()
        self.is_parallel = self.set_parallel_processing()

        self.add_queues()

    def set_parallel_processing(self):
        """ Set whether to run detect and align together or seperately """
        detector_vram = self.detector.vram
        aligner_vram = self.aligner.vram
        gpu_stats = GPUStats()
        if (detector_vram == 0
                or aligner_vram == 0
                or gpu_stats.device_count == 0):
            return True

        if hasattr(self.args, "multiprocess") and not self.args.multiprocess:
            print("\nNB: Parallel processing disabled.\nYou may get faster "
                  "extraction speeds by enabling it with the -mp switch\n")
            return False

        required_vram = detector_vram + aligner_vram + 320  # 320MB buffer
        stats = gpu_stats.get_card_most_free()
        free_vram = int(stats["free"])
        if self.args.verbose:
            print("{} - {}MB free of {}MB".format(stats["device"],
                                                  free_vram,
                                                  int(stats["total"])))
        if free_vram <= required_vram:
            if self.args.verbose:
                print("Not enough free VRAM for parallel processing. "
                      "Switching to serial")
            return False
        return True

    def add_queues(self):
        """ Add the required processing queues to Queue Manager """
        for task in ("load", "detect", "align", "save"):
            size = 0
            if task == "load" or (not self.is_parallel and task == "detect"):
                size = 100
            queue_manager.add_queue(task, maxsize=size)

    def load_detector(self):
        """ Set global arguments and load detector plugin """
        detector_name = self.args.detector.replace("-", "_").lower()

        # Rotation
        rotation = None
        if hasattr(self.args, "rotate_images"):
            rotation = self.args.rotate_images

        detector = PluginLoader.get_detector(detector_name)(
            verbose=self.args.verbose,
            rotation=rotation)

        return detector

    def load_aligner(self):
        """ Set global arguments and load aligner plugin """
        aligner_name = self.args.aligner.replace("-", "_").lower()

        # Align Eyes
        align_eyes = False
        if hasattr(self.args, 'align_eyes'):
            align_eyes = self.args.align_eyes

        # Extracted Face Size
        size = 256
        if hasattr(self.args, 'size'):
            size = self.args.size

        aligner = PluginLoader.get_aligner(aligner_name)(
            verbose=self.args.verbose,
            align_eyes=align_eyes,
            size=size)

        return aligner

    def launch_aligner(self):
        """ Launch the face aligner """
        out_queue = queue_manager.get_queue("align")
        kwargs = {"in_queue": queue_manager.get_queue("detect"),
                  "out_queue": out_queue}

        align_process = SpawnProcess()
        event = align_process.event

        align_process.in_process(self.aligner.align, **kwargs)

        # Wait for Aligner to take it's VRAM
        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Aligner")

    def launch_detector(self):
        """ Launch the face detector """
        out_queue = queue_manager.get_queue("detect")
        kwargs = {"in_queue": queue_manager.get_queue("load"),
                  "out_queue": out_queue}
        if self.args.detector == "mtcnn":
            mtcnn_kwargs = self.detector.validate_kwargs(
                self.get_mtcnn_kwargs())
            kwargs["mtcnn_kwargs"] = mtcnn_kwargs

        if self.detector.parent_is_pool:
            detect_process = PoolProcess(self.detector.detect_faces)
        else:
            detect_process = SpawnProcess()

        event = None
        if hasattr(detect_process, "event"):
            event = detect_process.event

        detect_process.in_process(self.detector.detect_faces, **kwargs)

        if not event:
            return

        event.wait(60)
        if not event.is_set():
            raise ValueError("Error inititalizing Detector")

    def get_mtcnn_kwargs(self):
        """ Add the mtcnn arguments into a kwargs dictionary """
        mtcnn_threshold = [float(thr.strip())
                           for thr in self.args.mtcnn_threshold]
        return {"minsize": self.args.mtcnn_minsize,
                "threshold": mtcnn_threshold,
                "factor": self.args.mtcnn_scalefactor}

    def detect_faces(self, extract_pass="detect"):
        """ Detect faces from in an image """
        if self.is_parallel or extract_pass == "align":
            out_queue = queue_manager.get_queue("align")
        if not self.is_parallel and extract_pass == "detect":
            out_queue = queue_manager.get_queue("detect")

        while True:
            try:
                faces = out_queue.get(True, 1)
                if faces == "EOF":
                    break
                exception = faces.get("exception", None)
                if exception is not None:
                    queue_manager.terminate_queues()
                    yield faces
                    break
            except QueueEmpty:
                continue

            yield faces
keep keep keep keep replace replace replace replace replace replace replace replace replace replace replace
 Extraction - Speed improvements (#522) (#523)

* Extraction - Speed improvements (#522)

* Initial Plugin restructure

* Detectors to plugins. Detector speed improvements

* Re-implement dlib aligner, remove models, FAN to TF. Parallel processing

* Update manual, update convert, implement parallel/serial switching

* linting + fix cuda check (setup.py). requirements update keras 2.2.4

* Add extract size option. Fix dlib hog init

* GUI: Increase tooltip width

* Update alignment tool to support new DetectedFace

* Add skip existing faces option

* Fix sort tool to new plugin structure

* remove old align plugin

* fix convert -skip faces bug

* Fix convert skipping no faces frames

* Convert - draw onto transparent layer

* Fix blur threshold bug

* fix skip_faces convert bug

* Fix training 
scripts/extract.py