                          [face.get("x", 0) + face.get("w", 0),
                           face.get("y", 0) + face.get("h", 0)],
                          [face.get("x", 0),
                           face.get("y", 0) + face.get("h", 0)]]
          landmarks = face.get("landmarksXY", list())
  
      # Bounding Box Dict
      elif isinstance(face, dict) and "left" in face:
          bounding_box = [[face["left"], face["top"]],
                          [face["right"], face["top"]],
                          [face["right"], face["bottom"]],
                          [face["left"], face["bottom"]]]
          landmarks = list()
  
      else:
          raise ValueError("Unsupported face type")
  
      logger.trace("Original landmarks: %s", landmarks)
 
</s> remove         landmarks = face.landmarksXY
 </s> add         landmarks = face.landmarks_xy </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     @staticmethod
    def recalculate_bounding_box(faces, landmarks):
        """ Recalculate the bounding box for Face Alignment.

            Resize the bounding box around features to present
            a better box to Face Alignment. Helps its chances
            on edge cases and helps remove 'jitter' """
        logger.trace("Recalculating Bounding Boxes: (faces: %s, landmarks: %s)",
                     faces, landmarks)
        retval = list()
        no_faces = len(faces)
        if no_faces == 0:
            return retval
        face_landmarks = np.hsplit(landmarks, no_faces)
        for idx in range(no_faces):
            pts = np.reshape(face_landmarks[idx], (5, 2), order="F")
            nose = pts[2]

            minmax = (np.amin(pts, axis=0), np.amax(pts, axis=0))
            padding = [(minmax[1][0] - minmax[0][0]) / 2,
                       (minmax[1][1] - minmax[0][1]) / 2]

            center = (minmax[1][0] - padding[0], minmax[1][1] - padding[1])
            offset = (center[0] - nose[0], nose[1] - center[1])
            center = (center[0] + offset[0], center[1] + offset[1])

            padding[0] += padding[0]
            padding[1] += padding[1]

            bounding = [center[0] - padding[0], center[1] - padding[1],
                        center[0] + padding[0], center[1] + padding[1]]
            retval.append(bounding)
        logger.trace("Recalculated Bounding Boxes: %s", retval)
        return retval


# MTCNN Detector for face alignment
# Code adapted from: https://github.com/davidsandberg/facenet

# Tensorflow implementation of the face detection / alignment algorithm
 </s> add     def process_input(self, batch):
        """ Compile the detection image(s) for prediction """
        batch["feed"] = (batch["scaled_image"] - 127.5) / 127.5
        return batch

    def predict(self, batch):
        """ Run model to get predictions """
        prediction, points = self.model.detect_faces(batch["feed"])
        logger.trace("filename: %s, prediction: %s, mtcnn_points: %s",
                     batch["filename"], prediction, points)
        batch["prediction"], batch["mtcnn_points"] = [prediction], [points]
        return batch

    def process_output(self, batch):
        """ Post process the detected faces """
        return batch


# MTCNN Detector
# Code adapted from: https://github.com/xiangrufan/keras-mtcnn
#
# Keras implementation of the face detection / alignment algorithm </s> remove             face.landmarksXY = rotated_landmarks
    elif isinstance(face, dict) and "x" in face:
        face["x"] = int(pt_x)
        face["y"] = int(pt_y)
        face["w"] = int(width)
        face["h"] = int(height)
        face["r"] = 0
        if len(rotated) > 1:
            rotated_landmarks = [tuple(point) for point in rotated[1].tolist()]
            face["landmarksXY"] = rotated_landmarks
 </s> add             face.landmarks_xy = rotated_landmarks
        landmarks = face.get("landmarks_xy", list())
                          [face.get("x", 0) + face.get("w", 0),
                           face.get("y", 0) + face.get("h", 0)],
                          [face.get("x", 0),
                           face.get("y", 0) + face.get("h", 0)]]
        landmarks = face.get("landmarks_xy", list())
        landmarks = face.get("landmarks_xy", list())
        landmarks = face.get("landmarks_xy", list())
        landmarks = face.get("landmarks_xy", list())
        landmarks = face.get("landmarks_xy", list())
        landmarks = face.get("landmarks_xy", list())
        landmarks = face.get("landmarks_xy", list())
        landmarks = face.get("landmarks_xy", list())
        landmarks = face.get("landmarks_xy", list())
  
      else:
          raise ValueError("Unsupported face type")
  
      logger.trace("Original landmarks: %s", landmarks)
keep keep keep keep replace replace replace replace replace replace replace replace replace keep keep keep keep keep
 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 
lib/utils.py