          pts_img = self.get_pts_from_predict(prediction, feed_dict["roi"])
          return pts_img
  
      @staticmethod
      def get_pts_from_predict(prediction, roi):
          """ Get points from predictor """
          logger.trace("Obtain points from prediction")
          points = np.array(prediction).flatten()
          points = np.reshape(points, (-1, 2))
          points *= (roi[2] - roi[0])
 
</s> remove         logger.trace("Obtain points from prediction")
        points = np.array(prediction).flatten()
        points = np.reshape(points, (-1, 2))
        points *= (roi[2] - roi[0])
        points[:, 0] += roi[0]
        points[:, 1] += roi[1]
        retval = np.rint(points).astype("uint").tolist()
        logger.trace("Predicted Landmarks: %s", retval)
        return retval
 </s> add         for prediction, roi in zip(batch["prediction"], batch["roi"]):
            points = np.array(prediction).flatten()
            points = np.reshape(points, (-1, 2))
            points *= (roi[2] - roi[0])
            points[:, 0] += roi[0]
            points[:, 1] += roi[1]
            landmarks = np.rint(points).astype("uint").tolist()
            batch.setdefault("landmarks", []).append(landmarks)
        logger.trace("Predicted Landmarks: %s", batch["landmarks"]) </s> remove         image = np.expand_dims(np.transpose(feed_dict["image"], (2, 0, 1)), 0).astype("float32")
        self.model.setInput(image)
        prediction = self.model.forward()
        pts_img = self.get_pts_from_predict(prediction, feed_dict["roi"])
        return pts_img
 </s> add         self.model.setInput(batch["feed"])
        batch["prediction"] = self.model.forward()
        return batch

    def process_output(self, batch):
        """ Process the output from the model """
        self.get_pts_from_predict(batch)
        return batch </s> remove         image = np.expand_dims(
            feed_dict["image"].transpose((2, 0, 1)).astype(np.float32) / 255.0, 0)
        prediction = self.model.predict(image)[-1]
        pts_img = self.get_pts_from_predict(prediction, feed_dict["center"], feed_dict["scale"])
        retval = [(int(pt[0]), int(pt[1])) for pt in pts_img]
        logger.trace("Predicted Landmarks: %s", retval)
        return retval
 </s> add         batch["prediction"] = self.model.predict(batch["feed"])[-1]
        logger.trace([pred.shape for pred in batch["prediction"]])
        return batch

    def process_output(self, batch):
        """ Process the output from the model """
        self.get_pts_from_predict(batch)
        return batch </s> remove     def get_pts_from_predict(self, prediction, center, scale):
 </s> add     def get_pts_from_predict(self, batch): </s> remove         ident = sum(t.startswith(prefix) for t, _ in self.layers.items()) + 1
        return '%s_%d' % (prefix, ident)

    def make_var(self, name, shape):
        """Creates a new TensorFlow variable."""
        return tf.get_variable(name, shape, trainable=self.trainable)

    @staticmethod
    def validate_padding(padding):
        """Verifies that the padding is one of the supported ones."""
        assert padding in ('SAME', 'VALID')

    @layer
    def conv(self,  # pylint: disable=too-many-arguments
             inp,
             k_h,
             k_w,
             c_o,
             s_h,
             s_w,
             name,
             relu=True,
             padding='SAME',
             group=1,
             biased=True):
        """ Conv Layer """
 </s> add         total_boxes = np.empty((0, 9))
        points = np.empty(0)
        # TODO Implement batch support
        image = batch[0]
        origin_h, origin_w = image.shape[:2]
        rectangles = self.detect_pnet(image, origin_h, origin_w)
        if not rectangles:
            return total_boxes, points
        rectangles = self.detect_rnet(image, rectangles, origin_h, origin_w)
        if not rectangles:
            return total_boxes, points
        rectangles = self.detect_onet(image, rectangles, origin_h, origin_w)
        if rectangles:
            total_boxes = np.array([result[:5] for result in rectangles])
            points = np.array([result[5:] for result in rectangles]).T
        return total_boxes, points

    def detect_pnet(self, image, height, width):
    def get_pts_from_predict(batch):
          pts_img = self.get_pts_from_predict(prediction, feed_dict["roi"])
          return pts_img
  
      @staticmethod
    def get_pts_from_predict(batch):
          """ Get points from predictor """
          logger.trace("Obtain points from prediction")
          points = np.array(prediction).flatten()
          points = np.reshape(points, (-1, 2))
          points *= (roi[2] - roi[0])
keep keep keep keep 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 
plugins/extract/align/cv2_dnn.py