                         int(vram["free"]),
                         int(vram["total"]))
          return int(vram["card_id"]), int(vram["free"]), int(vram["total"])
  
      @staticmethod
      def to_bounding_box_dict(left, top, right, bottom):
          """ Return a dict for the bounding box """
          return dict(left=int(round(left)),
                      right=int(round(right)),
                      top=int(round(top)),
                      bottom=int(round(bottom)))
  
      def set_predetected(self, width, height):
          """ Set a bounding box dict for predetected faces """
          # Predetected_face is used for sort tool.
          # Landmarks should not be extracted again from predetected faces,
          # because face data is lost, resulting in a large variance
          # against extract from original image
          logger.debug("Setting predetected face")
          return [self.to_bounding_box_dict(0, 0, width, height)]
 
</s> remove                                (rotated_width, rotated_height)),
                rotation_matrix)

    # << QUEUE METHODS >> #
    def get_item(self):
        """ Yield one item from the queue """
        item = self.queues["in"].get()
        if isinstance(item, dict):
            logger.trace("Item in: %s", item["filename"])
        else:
            logger.trace("Item in: %s", item)
        if item == "EOF":
            logger.debug("In Queue Exhausted")
            # Re-put EOF into queue for other threads
            self.queues["in"].put(item)
        return item

    def get_batch(self):
        """ Get items from the queue in batches of
            self.batch_size

            First item in output tuple indicates whether the
            queue is exhausted.
            Second item is the batch

            Remember to put "EOF" to the out queue after processing
            the final batch """
        exhausted = False
        batch = list()
        for _ in range(self.batch_size):
            item = self.get_item()
            if item == "EOF":
                exhausted = True
                break
            batch.append(item)
        logger.trace("Returning batch size: %s", len(batch))
        return (exhausted, batch)

    # <<< MISC METHODS >>> #
    def get_vram_free(self):
        """ Return free and total VRAM on card with most VRAM free"""
        stats = GPUStats()
        vram = stats.get_card_most_free(supports_plaidml=self.supports_plaidml)
        logger.verbose("Using device %s with %sMB free of %sMB",
                       vram["device"],
                       int(vram["free"]),
                       int(vram["total"]))
        return int(vram["card_id"]), int(vram["free"]), int(vram["total"])
 </s> add                                (self.input_size, self.input_size))
        if channels_first:
            image = np.moveaxis(image, 2, 0) </s> remove     def landmarks_as_xy(self):
        """ Landmarks as XY """
        return self.landmarksXY

    def to_bounding_box_dict(self):
        """ Return Bounding Box as a bounding box dixt """
        retval = dict(left=self.x, top=self.y, right=self.x + self.w, bottom=self.y + self.h)
        logger.trace("Returning: %s", retval)
        return retval

    def from_bounding_box_dict(self, bounding_box_dict, image=None):
        """ Set Bounding Box from a bounding box dict """
        logger.trace("Creating from bounding box dict: %s", bounding_box_dict)
        if not isinstance(bounding_box_dict, dict):
            raise ValueError("Supplied Bounding Box is not a dictionary.")
        self.x = bounding_box_dict["left"]
        self.w = bounding_box_dict["right"] - bounding_box_dict["left"]
        self.y = bounding_box_dict["top"]
        self.h = bounding_box_dict["bottom"] - bounding_box_dict["top"]
        if image is not None and image.any():
            self.image_to_face(image)
        logger.trace("Created from bounding box dict: (x: %s, w: %s, y: %s. h: %s)",
                     self.x, self.w, self.y, self.h)
 </s> add     def top(self):
        """int: Top point (in pixels) of face detection bounding box within the parent image """
        return self.y </s> remove     def initialize(self, *args, **kwargs):
        """ Create the mtcnn detector """
        super().initialize(*args, **kwargs)
        logger.info("Initializing Manual Detector...")
        self.init.set()
        logger.info("Initialized Manual Detector.")

    def detect_faces(self, *args, **kwargs):
        """ Return the given bounding box in a bounding box dict """
        super().detect_faces(*args, **kwargs)
        while True:
            item = self.get_item()
            if item == "EOF":
                break
            face = item["face"]

            bounding_box = [self.to_bounding_box_dict(face[0], face[1], face[2], face[3])]
            item["detected_faces"] = bounding_box
            self.finalize(item)

        self.queues["out"].put("EOF")
 </s> add     def _compile_detection_image(self, input_image):
        """ Override compile detection image for manual. No face is actually fed into a model """
        return input_image, 1, (0, 0)

    def init_model(self):
        """ No model for Manual """
        return

    def process_input(self, batch):
        """ No pre-processing for Manual. Just set a dummy feed """
        batch["feed"] = batch["scaled_image"]
        return batch

    def predict(self, batch):
        """ No prediction for Manual """
        batch["prediction"] = [np.array(batch["manual_face"])]
        return batch

    def process_output(self, batch):
        """ Post process the detected faces """
        return batch </s> remove 
    # <<< FINALIZE METHODS >>> #
    def finalize(self, output):
        """ This should be called as the final task of each plugin
            aligns faces and puts to the out queue """
        if output == "EOF":
            logger.trace("Item out: %s", output)
            self.queues["out"].put("EOF")
            return
        logger.trace("Item out: %s", {key: val
                                      for key, val in output.items()
                                      if key != "image"})
        self.queues["out"].put((output))

    # <<< MISC METHODS >>> #
    def get_vram_free(self):
        """ Return free and total VRAM on card with most VRAM free"""
        stats = GPUStats()
        vram = stats.get_card_most_free(supports_plaidml=self.supports_plaidml)
        logger.verbose("Using device %s with %sMB free of %sMB",
                       vram["device"],
                       int(vram["free"]),
                       int(vram["total"]))
        return int(vram["card_id"]), int(vram["free"]), int(vram["total"])

    def get_item(self):
        """ Yield one item from the queue """
        while True:
            item = self.queues["in"].get()
            if isinstance(item, dict):
                logger.trace("Item in: %s", {key: val
                                             for key, val in item.items()
                                             if key != "image"})
                # Pass Detector failures straight out and quit
                if item.get("exception", None):
                    self.queues["out"].put(item)
                    exit(1)
            else:
                logger.trace("Item in: %s", item)
            yield item
            if item == "EOF":
                break
 </s> add  </s> remove         Pass in a DetectedFace object, Alignments dict or bounding box dict
        (as defined in lib/plugins/extract/detect/_base.py) """
 </s> add         Pass in a DetectedFace object or Alignments dict """
        return image, rotation_matrix
                         int(vram["free"]),
                         int(vram["total"]))
          return int(vram["card_id"]), int(vram["free"]), int(vram["total"])
  
        return image, rotation_matrix
        return image, rotation_matrix
        return image, rotation_matrix
        return image, rotation_matrix
        return image, rotation_matrix
        return image, rotation_matrix
        return image, rotation_matrix
        return image, rotation_matrix
        return image, rotation_matrix
        return image, rotation_matrix
        return image, rotation_matrix
        return image, rotation_matrix
        return image, rotation_matrix
        return image, rotation_matrix
        return image, rotation_matrix
        return image, rotation_matrix
keep keep keep keep replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace
 De-Multiprocess Extract (#871)

* requirements.txt: - Pin opencv to 4.1.1 (fixes cv2-dnn error)

* lib.face_detect.DetectedFace: change LandmarksXY to landmarks_xy. Add left, right, top, bottom attributes

* lib.model.session: Session manager for loading models into different graphs (for Nvidia + CPU)

* plugins.extract._base: New parent class for all extract plugins

* plugins.extract.pipeline. Remove MultiProcessing. Dynamically limit batchsize for Nvidia cards. Remove loglevel input

* S3FD + FAN plugins. Standardise to Keras version for all backends

* Standardize all extract plugins to new threaded codebase

* Documentation. Start implementing Numpy style docstrings for Sphinx Documentation

* Remove s3fd_amd. Change convert OTF to expect DetectedFace object

* faces_detect - clean up and documentation

* Remove PoolProcess

* Migrate manual tool to new extract workflow

* Remove AMD specific extractor code from cli and plugins

* Sort tool to new extract workflow

* Remove multiprocessing from project

* Remove multiprocessing queues from QueueManager

* Remove multiprocessing support from logger

* Move face_filter to new extraction pipeline

* Alignments landmarksXY > landmarks_xy and legacy handling

* Intercept get_backend for sphinx doc build

# Add Sphinx documentation 
plugins/extract/detect/_base.py