          if (not hasattr(self.args, 'debug_landmarks')
                  or not self.args.debug_landmarks):
              return
  
          for (pos_x, pos_y) in face.landmarks_as_xy():
              cv2.circle(image, (pos_x, pos_y), 2, (0, 0, 255), -1)
  
      def detect_blurry_faces(self, face, t_mat, resized_image, filename):
          """ Detect and move blurry face """
          if not hasattr(self.args, 'blur_thresh') or not self.args.blur_thresh:
              return None
 
</s> remove     def detect_blurry_faces(self, face, t_mat, resized_image, filename):
        """ Detect and move blurry face """
        if not hasattr(self.args, 'blur_thresh') or not self.args.blur_thresh:
            return None
 </s> add         return input_images </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) </s> remove         blurry_file = None
        aligned_landmarks = self.extractor.transform_points(
            face.landmarks_as_xy(),
            t_mat,
            256,
            48)
        feature_mask = self.extractor.get_feature_mask(aligned_landmarks / 256,
                                                       256,
                                                       48)
        feature_mask = cv2.blur(feature_mask, (10, 10))
        isolated_face = cv2.multiply(
            feature_mask,
            resized_image.astype(float)).astype(np.uint8)
        blurry, focus_measure = is_blurry(isolated_face, self.args.blur_thresh)

        if blurry:
            print("{}'s focus measure of {} was below the blur threshold, "
                  "moving to \"blurry\"".format(Path(filename).stem,
                                                focus_measure))
            blurry_file = get_folder(Path(self.output_dir) /
                                     Path("blurry")) / Path(filename).stem
        return blurry_file
 </s> add     def load(self):
        """ Load an image and yield it with it's filename """
        for filename in self.input_images:
            yield filename, cv2.imread(filename) </s> remove         self.serializer = self.get_serializer()
        self.alignments_path = self.get_alignments_path()
        self.have_alignments_file = os.path.exists(self.alignments_path)
 </s> add         self.verbose = self.args.verbose
        self.actions = self.set_actions()

    def get_items(self):
        """ Set the post processing actions """
        postprocess_items = dict()
        # Debug Landmarks
        if (hasattr(self.args, 'debug_landmarks')
                and self.args.debug_landmarks):
            postprocess_items["DebugLandmarks"] = None

        # Blurry Face
        if hasattr(self.args, 'blur_thresh') and self.args.blur_thresh:
            kwargs = {"blur_thresh": self.args.blur_thresh}
            postprocess_items["BlurryFaceFilter"] = {"kwargs": kwargs}

        # Face Filter post processing
        if ((hasattr(self.args, "filter") and self.args.filter is not None) or
                (hasattr(self.args, "nfilter") and
                 self.args.nfilter is not None)):
            face_filter = dict()
            filter_lists = dict()
            if hasattr(self.args, "ref_threshold"):
                face_filter["ref_threshold"] = self.args.ref_threshold
            for filter_type in ('filter', 'nfilter'):
                filter_args = getattr(self.args, filter_type, None)
                filter_args = None if not filter_args else filter_args
                filter_lists[filter_type] = filter_args
            face_filter["filter_lists"] = filter_lists
            postprocess_items["FaceFilter"] = {"kwargs": face_filter}

        return postprocess_items

    def set_actions(self):
        """ Compile the actions to be performed into a list """
        postprocess_items = self.get_items()
        actions = list()
        for action, options in postprocess_items.items():
            options = dict() if options is None else options
            args = options.get("args", tuple())
            kwargs = options.get("kwargs", dict())
            args = args if isinstance(args, tuple) else tuple()
            kwargs = kwargs if isinstance(kwargs, dict) else dict()
            kwargs["verbose"] = self.verbose
            task = globals()[action](*args, **kwargs)
            actions.append(task)

        for action in actions:
            action_name = camel_case_split(action.__class__.__name__)
            print("Adding post processing item: "
                  "{}".format(" ".join(action_name)))

        return actions

    def do_actions(self, output_item):
        """ Perform the requested post-processing actions """
        for action in self.actions:
            action.process(output_item)


class PostProcessAction():
    """ Parent class for Post Processing Actions
        Usuable in Extract or Convert or both
        depending on context """
    def __init__(self, *args, **kwargs):
        self.verbose = kwargs["verbose"]

    def process(self, output_item):
        """ Override for specific post processing action """
        raise NotImplementedError


class BlurryFaceFilter(PostProcessAction):
    """ Move blurry faces to a different folder
        Extract Only """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.blur_thresh = kwargs["blur_thresh"]

    def process(self, output_item):
        """ Detect and move blurry face """
        extractor = AlignerExtract()

        for idx, face in enumerate(output_item["detected_faces"]):
            resized_face = output_item["resized_faces"][idx]
            dims = resized_face.shape[:2]
            size = dims[0]
            t_mat = output_item["t_mats"][idx]

            aligned_landmarks = extractor.transform_points(
                face.landmarksXY,
                t_mat, size, 48)
            feature_mask = extractor.get_feature_mask(
                aligned_landmarks / size,
                size, 48)
            feature_mask = cv2.blur(feature_mask, (10, 10))
            isolated_face = cv2.multiply(
                feature_mask,
                resized_face.astype(float)).astype(np.uint8)
            blurry, focus_measure = is_blurry(isolated_face, self.blur_thresh)

            if blurry:
                blur_folder = output_item["output_file"].parts[:-1]
                blur_folder = get_folder(Path(*blur_folder) / Path("blurry"))
                frame_name = output_item["output_file"].parts[-1]
                output_item["output_file"] = blur_folder / Path(frame_name)
                if self.verbose:
                    print("{}'s focus measure of {} was below the blur "
                          "threshold, moving to \"blurry\"".format(
                              frame_name, focus_measure))


class DebugLandmarks(PostProcessAction):
    """ Draw debug landmarks on face
        Extract Only """

    def process(self, output_item):
        """ Draw landmarks on image """
        transform_points = AlignerExtract().transform_points
        for idx, face in enumerate(output_item["detected_faces"]):
            dims = output_item["resized_faces"][idx].shape[:2]
            size = dims[0]
            landmarks = transform_points(face.landmarksXY,
                                         output_item["t_mats"][idx],
                                         size,
                                         48)
            for (pos_x, pos_y) in landmarks:
                cv2.circle(output_item["resized_faces"][idx],
                           (pos_x, pos_y), 2, (0, 0, 255), -1)


class FaceFilter(PostProcessAction):
    """ Filter in or out faces based on input image(s)
        Extract or Convert """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        filter_lists = kwargs["filter_lists"]
        ref_threshold = kwargs.get("ref_threshold", 0.6)
        self.filter = self.load_face_filter(filter_lists, ref_threshold)

    def load_face_filter(self, filter_lists, ref_threshold):
        """ Load faces to filter out of images """
        if not any(val for val in filter_lists.values()):
            return None </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())
        print("Input Directory: {}".format(self.args.input_dir))
        input_images = get_image_paths(self.args.input_dir)
          if (not hasattr(self.args, 'debug_landmarks')
                  or not self.args.debug_landmarks):
              return
  
        print("Input Directory: {}".format(self.args.input_dir))
        input_images = get_image_paths(self.args.input_dir)
        print("Input Directory: {}".format(self.args.input_dir))
        input_images = get_image_paths(self.args.input_dir)
  
      def detect_blurry_faces(self, face, t_mat, resized_image, filename):
          """ Detect and move blurry face """
          if not hasattr(self.args, 'blur_thresh') or not self.args.blur_thresh:
              return None
keep keep keep keep 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