          self.already_processed = self.get_already_processed()
          self.input_images = self.get_input_images()
          self.images_found = len(self.input_images)
  
          self.rotation_width = 0
          self.rotation_height = 0
  
      def get_rotation_angles(self):
          """ Set the rotation angles. Includes backwards compatibility for the
              'on' and 'off' options:
                  - 'on' - increment 90 degrees
                  - 'off' - disable
                  - 0 is prepended to the list, as whatever happens, we want to
                    scan the image in it's upright state """
          rotation_angles = [0]
  
          if (not hasattr(self.args, 'rotate_images')
                  or not self.args.rotate_images
                  or self.args.rotate_images == "off"):
              return rotation_angles
  
          if self.args.rotate_images == "on":
              rotation_angles.extend(range(90, 360, 90))
          else:
              passed_angles = [int(angle)
                               for angle in self.args.rotate_images.split(",")]
              if len(passed_angles) == 1:
                  rotation_step_size = passed_angles[0]
                  rotation_angles.extend(range(rotation_step_size,
                                               360,
                                               rotation_step_size))
              elif len(passed_angles) > 1:
                  rotation_angles.extend(passed_angles)
  
          return rotation_angles
  
      def get_already_processed(self):
          """ Return the images that already exist in the output directory """
          print("Output Directory: {}".format(self.args.output_dir))
  
          if (not hasattr(self.args, 'skip_existing')
                  or not self.args.skip_existing):
              return None
  
          return get_image_paths(self.args.output_dir)
  
      def get_input_images(self):
          """ Return the list of images that are to be processed """
 
</s> remove         return get_image_paths(self.args.output_dir)
 </s> add     def faces_count(self):
        """ Return current faces count """
        return sum(len(faces) for faces in self.data.values()) </s> remove     def get_input_images(self):
        """ Return the list of images that are to be processed """
        if not os.path.exists(self.args.input_dir):
            print("Input directory {} not found.".format(self.args.input_dir))
            exit(1)

        print("Input Directory: {}".format(self.args.input_dir))
 </s> add     def get_serializer(self):
        """ Set the serializer to be used for loading and
            saving alignments """
        if (not hasattr(self.args, "serializer")
                or not self.args.serializer):
            if self.args.alignments_path:
                ext = os.path.splitext(self.args.alignments_path)[-1]
            else:
                ext = "json"
            serializer = Serializer.get_serializer_from_ext(ext)
        else:
            serializer = Serializer.get_serializer(self.args.serializer)
        print("Using {} serializer".format(serializer.ext))
        return serializer </s> remove         self.rotation_angles = self.get_rotation_angles()
        self.already_processed = self.get_already_processed()
        self.input_images = self.get_input_images()
        self.images_found = len(self.input_images)
 </s> add         self.serializer = self.get_serializer()
        self.location = self.get_location()
        self.have_alignments_file = os.path.exists(self.location)
        self.data = self.load() </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 </s> remove             yield faces_count, face
            self.num_faces_detected += 1
            faces_count += 1
        if faces_count > 1 and self.args.verbose:
            print("Note: Found more than one face in "
                  "an image! File: {}".format(filename))
            self.verify_output = True

    def draw_landmarks_on_face(self, face, image):
        """ Draw debug landmarks on extracted face """
        if (not hasattr(self.args, 'debug_landmarks')
                or not self.args.debug_landmarks):
            return
 </s> add     def get_input_images(self):
        """ Return the list of images that are to be processed """
        if not os.path.exists(self.args.input_dir):
            print("Input directory {} not found.".format(self.args.input_dir))
            exit(1)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
          self.already_processed = self.get_already_processed()
          self.input_images = self.get_input_images()
          self.images_found = len(self.input_images)
  
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
    def frames_count(self):
        """ Return current frames count """
        return len(self.data)
  
          return get_image_paths(self.args.output_dir)
  
      def get_input_images(self):
          """ Return the list of images that are to be processed """
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 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