          self.faces_detected = dict()
          self.num_faces_detected = 0
          self.verify_output = False
  
      @staticmethod
      def load_extractor(extractor_name="Align"):
          """ Load the requested extractor for extraction """
          extractor = PluginLoader.get_extractor(extractor_name)()
  
          return extractor
  
      def get_mtcnn_kwargs(self):
          """ Add the mtcnn arguments into a kwargs dictionary """
 
</s> remove         self.faces_detected = dict()
        self.num_faces_detected = 0
        self.verify_output = False
 </s> add         return data </s> remove     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}
 </s> add     @staticmethod
    def get_original_rotation_matrix(dimensions, angle):
        """ Calculate original rotation matrix and invert """
        height, width = dimensions
        center = (width/2, height/2)
        rotation_matrix = cv2.getRotationMatrix2D(center, -1.0*angle, 1.) </s> remove         return extractor
 </s> add     def frame_exists(self, frame):
        """ return path of images that have faces """
        return frame in self.data.keys()

    def get_alignments_for_frame(self, frame):
        """ Return the alignments for the selected frame """
        return self.data.get(frame, list())

    def get_legacy_frames(self):
        """ Return a list of frames with legacy rotations """
        keys = list()
        for key, val in self.data.items():
            if any(alignment.get("r", None) for alignment in val):
                keys.append(key)
        return keys

    def rotate_existing_landmarks(self, frame, dimensions):
        """ Backwards compatability fix. Rotates the landmarks to
            their correct position and deletes r """
        for face in self.get_alignments_for_frame(frame):
            angle = face.get("r", 0)
            if not angle:
                return
            rotation_matrix = self.get_original_rotation_matrix(dimensions,
                                                                angle)
            rotate_landmarks(face, rotation_matrix)
            del face["r"] </s> remove class Faces():
    """ Holds the faces """
    def __init__(self, arguments):
        self.args = arguments
        self.extractor = self.load_extractor()
        self.mtcnn_kwargs = self.get_mtcnn_kwargs()
        self.filter = self.load_face_filter()
        self.align_eyes = self.args.align_eyes if hasattr(
            self.args, 'align_eyes') else False
        self.output_dir = get_folder(self.args.output_dir)
 </s> add         if skip_faces:
            # Remove items from algnments that have no faces so they will
            # be re-detected
            del_keys = [key for key, val in data.items() if not val]
            for key in del_keys:
                if key in data:
                    del data[key] </s> remove         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> add 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
    def save(self):
        """ Write the serialized alignments file """
        try:
            print("Writing alignments to: {}".format(self.location))
            with open(self.location, self.serializer.woptions) as align:
                align.write(self.serializer.marshal(self.data))
        except Exception as err:
            print("{} not written!".format(self.location))
            print(str(err))
          self.faces_detected = dict()
          self.num_faces_detected = 0
          self.verify_output = False
  
    def save(self):
        """ Write the serialized alignments file """
        try:
            print("Writing alignments to: {}".format(self.location))
            with open(self.location, self.serializer.woptions) as align:
                align.write(self.serializer.marshal(self.data))
        except Exception as err:
            print("{} not written!".format(self.location))
            print(str(err))
    def save(self):
        """ Write the serialized alignments file """
        try:
            print("Writing alignments to: {}".format(self.location))
            with open(self.location, self.serializer.woptions) as align:
                align.write(self.serializer.marshal(self.data))
        except Exception as err:
            print("{} not written!".format(self.location))
            print(str(err))
    def save(self):
        """ Write the serialized alignments file """
        try:
            print("Writing alignments to: {}".format(self.location))
            with open(self.location, self.serializer.woptions) as align:
                align.write(self.serializer.marshal(self.data))
        except Exception as err:
            print("{} not written!".format(self.location))
            print(str(err))
    def save(self):
        """ Write the serialized alignments file """
        try:
            print("Writing alignments to: {}".format(self.location))
            with open(self.location, self.serializer.woptions) as align:
                align.write(self.serializer.marshal(self.data))
        except Exception as err:
            print("{} not written!".format(self.location))
            print(str(err))
  
          return extractor
  
      def get_mtcnn_kwargs(self):
          """ Add the mtcnn arguments into a kwargs dictionary """
keep keep keep keep replace replace replace replace keep keep keep keep keep
 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/fsmedia.py