          return sorted([item for item in self.process_folder()],
                        key=lambda x: (x["frame_name"]))
  
  
  class DetectedFace():
      """ Detected face and landmark information """
      def __init__(self):
          self.image = None
          self.x = None
          self.w = None
          self.y = None
          self.h = None
          self.landmarksXY = None
  
      def alignment_to_face(self, image, alignment):
          """ Convert a face alignment to detected face object """
          self.image = image
          self.x = alignment["x"]
          self.w = alignment["w"]
          self.y = alignment["y"]
          self.h = alignment["h"]
          self.landmarksXY = alignment["landmarksXY"]
  
      def face_to_alignment(self, alignment):
          """ Convert a face alignment to detected face object """
          alignment["x"] = self.x
          alignment["w"] = self.w
          alignment["y"] = self.y
          alignment["h"] = self.h
          alignment["landmarksXY"] = self.landmarksXY
          return alignment
  
      def landmarks_as_xy(self):
          """ Landmarks as XY """
          return self.landmarksXY
  
  
  class ExtractedFaces():
      """ Holds the extracted faces and matrix for
          alignments """
      def __init__(self, frames, alignments, size=256,
                   padding=48, align_eyes=False):
 
</s> remove         self.r = r
 </s> add  </s> remove     def __init__(self, image=None, r=0, x=None,
                 w=None, y=None, h=None, landmarksXY=None):
 </s> add     def __init__(self, image=None, x=None, w=None, y=None, h=None,
                 landmarksXY=None): </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     def write_alignments(self):
        """ Save the alignments file """
        self.alignments.write_alignments(self.faces.faces_detected)
 </s> add     def reload_images(self, detected_faces):
        """ Reload the images and pair to detected face """
        load_queue = queue_manager.get_queue("detect")
        for filename, image in self.images.load():
            detect_item = detected_faces.pop(filename, None)
            if not detect_item:
                continue
            detect_item["image"] = image
            load_queue.put(detect_item)
        load_queue.put("EOF") </s> remove             face = DetectedFace()
            face.alignment_to_face(None, alignment)
            face = rotate_landmarks(face, rotation_matrix)
            alignment = face.face_to_alignment(alignment)
 </s> add             rotate_landmarks(alignment, rotation_matrix)
          return sorted([item for item in self.process_folder()],
                        key=lambda x: (x["frame_name"]))
  
  

































  class ExtractedFaces():
      """ Holds the extracted faces and matrix for
          alignments """
      def __init__(self, frames, alignments, size=256,
                   padding=48, align_eyes=False):
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 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 
tools/lib_alignments/media.py