              if frame_no == self.save_interval:
                  self.write_alignments()
                  frame_no = 0
  
      def process_single_image(self, filename):
          """ Detect faces in an image. Rotate the image the specified amount
              until at least one face is found, or until image rotations are
              depleted.
              Once at least one face has been detected, pass to
              process_single_face to process the individual faces """
          retval = filename, list()
          try:
              image = Utils.cv2_read_write('read', filename)
  
              for angle in self.images.rotation_angles:
                  currentimage, rotation_matrix = rotate_image_by_angle(image,
                                                                        angle)
                  faces = self.faces.get_faces(currentimage, angle)
                  process_faces = [[idx, face] for idx, face in faces]
                  if not process_faces:
                      continue
  
                  if angle != 0 and self.args.verbose:
                      print("found face(s) by rotating image "
                            "{} degrees".format(angle))
                  if angle != 0:
                      process_faces = [[idx,
                                        rotate_landmarks(face, rotation_matrix)]
                                       for idx, face in process_faces]
  
                  if process_faces:
                      break
  
              final_faces = [self.process_single_face(idx,
                                                      face,
                                                      filename,
                                                      image)
 
</s> remove                 self.write_alignments()
 </s> add                 self.alignments.save() </s> remove             final_faces = [self.process_single_face(idx,
                                                    face,
                                                    filename,
                                                    image)
                           for idx, face in process_faces]
 </s> add     def process_item_count(self):
        """ Return the number of items to be processedd """
        processed = sum(os.path.basename(frame) in self.alignments.data.keys()
                        for frame in self.images.input_images) </s> remove     def have_face(self, filename):
        """ return path of images that have faces """
        return os.path.basename(filename) in self.faces_detected

    def get_faces(self, image, rotation=0):
        """ Extract the faces from an image """
        faces_count = 0
        faces = detect_faces(image,
                             self.args.detector,
                             self.args.verbose,
                             rotation=rotation,
                             dlib_buffer=self.args.dlib_buffer,
                             mtcnn_kwargs=self.mtcnn_kwargs)

        for face in faces:
            if self.filter and not self.filter.check(face):
                if self.args.verbose:
                    print("Skipping not recognized face!")
                continue
            yield faces_count, face

            self.num_faces_detected += 1
            faces_count += 1

        if faces_count > 1 and self.args.verbose:
            self.verify_output = True

    def get_faces_alignments(self, filename, image):
        """ Retrieve the face alignments from an image """
        faces_count = 0
        faces = self.faces_detected[os.path.basename(filename)]
        for rawface in faces:
            face = DetectedFace(**rawface)
            # Rotate the image if necessary
            # NB: Rotation of landmarks now occurs at extract stage
            # This is here for legacy alignments
            if face.r != 0:
                image, _ = rotate_image_by_angle(image, face.r)
            face.image = image[face.y: face.y + face.h,
                               face.x: face.x + face.w]
            if self.filter and not self.filter.check(face):
                if self.args.verbose:
                    print("Skipping not recognized face!")
                continue
 </s> add class Images():
    """ Holds the full frames/images """
    def __init__(self, arguments):
        self.args = arguments
        self.input_images = self.get_input_images()
        self.images_found = len(self.input_images) </s> remove             retval = filename, final_faces
        except Exception as err:
            if self.args.verbose:
                print("Failed to extract from image: "
                      "{}. Reason: {}".format(filename, err))
            raise
        return retval
 </s> add         if processed != 0 and self.args.skip_existing:
            print("Skipping {} previously extracted frames".format(processed))
        if processed != 0 and self.args.skip_faces:
            print("Skipping {} frames with detected faces".format(processed))

        to_process = self.images.images_found - processed
        if to_process == 0:
            print("No frames to process. Exiting")
            queue_manager.terminate_queues()
            exit(0)
        return to_process

    def run_detection(self, to_process):
        """ Run detection only """
        self.plugins.launch_detector()
        detected_faces = dict()
        for detected in tqdm(self.plugins.detect_faces(extract_pass="detect"),
                             total=to_process,
                             file=sys.stdout,
                             desc="Detecting faces"):
            exception = detected.get("exception", False)
            if exception:
                break

            del detected["image"]
            filename = detected["filename"]

            detected_faces[filename] = detected </s> remove                 for idx, face in faces:
 </s> add                 for idx, face in enumerate(faces):
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
              if frame_no == self.save_interval:
                  self.write_alignments()
                  frame_no = 0
  
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
        if self.export_face:
            queue_manager.get_queue("save").put("EOF")
        save_thread.join_threads()
  
              final_faces = [self.process_single_face(idx,
                                                      face,
                                                      filename,
                                                      image)
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 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/extract.py