code: def compute_pic_metric(
      img: np.ndarray,
      saliency_map: np.ndarray,
      random_mask: np.ndarray,
      pred_func: Callable[[np.ndarray], Sequence[float]],
      saliency_thresholds: Sequence[float],
      min_pred_value: float = 0.8,
      keep_monotonous: bool = True,
      num_data_points: int = 1000,
  ) -> PicMetricResult:
      """Computes Performance Information Curve for a single image.
  
      The method can be used to compute either Softmax Information Curve (SIC) or
      Accuracy Information Curve (AIC). The method computes the curve for a single
      image and saliency map. This method should be called repeatedly on different
      images and saliency maps.
  
      Args:
        img: an original image on which the curve should be computed. The numpy
          array should have dimensions [H, W, C] for a color image or [H, W]
          for a grayscale image. The array should be of type uint8.
        saliency_map: the saliency map for which the metric should be calculated.
          Usually, the saliency map should be calculated with respect to the
          same class label as the class label for which `pred_func` returns the
          prediction. However, the class labels may be different if you want
          to see how saliency for one class explains prediction of other class.
          Pixels with higher values are considered to be of higher importance.
          It is the responsibility of the caller to decide on the order of pixel
          importance, e.g. if the absolute values should be used instead of the
          signed ones, the caller should apply 'abs' function before calling this
          method. The shape of `saliency_map` is [H, W].
        random_mask: a random mask to use in order to create the initial
          completely blurred image.
        pred_func: a function that the method should call in order to obtain
          the prediction of a model on a batch of images. The method should accept
          a numpy array of type uint8 with dimensions [B, H, W, C] for color
          images or [B, H, W] for grayscale images and return the predictions
          as a list of float values. For multiclass classification, it is
          up to the implementer of the function to return the prediction for
          the desired class. For the SIC metric, the function should return the
          softmax of the corresponding class. For the AIC metric, the function
          should return 1.0 if the classification was correct and 0.0 otherwise.
          Note, that the images are passed as an uint8 array. If the underlying
          model requires a different format, it is the responsibility of the
          function implementer to do the corresponding conversion inside
          `pred_func`. See the accompanying Jupyter notebook for an example.
        saliency_thresholds: the thresholds represent the fractions of the most
          important saliency pixels that will be used to reconstruct
          intermediate blurred images and pass them to the model for evaluation.
          The value of this argument should be the list of thresholds in
          ascending order. Example value: [0.005, 0.01, 0.02, 0.03, 0.04, 0.05,
          0.07, 0.10, 0.13, 0.21, 0.34, 0.5, 0.75].
        min_pred_value: used for filtering images. If the model prediction on the
          original image is lower than the value of this argument, the method
          raises ComputePicMetricError to indicate that the image should be
          skipped. This is done to filter out images that produce low prediction
          confidence.
        keep_monotonous: whether to keep the curve monotonically increasing.
          The value of this argument was set to 'True' in the original paper but
          setting it to 'False' is a viable alternative.
        num_data_points: the number of PIC curve data points to return. The number
          excludes point 1.0 on the x-axis that is always appended to the end.
          E.g., value 1000 results in 1001 points evently distributed on the
          x-axis from 0.0 to 1.0 with 0.001 increment.
  
      Returns:
        The PIC curve data points and extra auxiliary information. See
        `PicMetricResult` for more information.
  
      Raises:
        ComputePicMetricError:
          The method raises the error in two cases. That happens in two cases:
          1. If the model prediction on the original image is not higher than the
             model prediction on the completely blurred image.
          2. If the entropy of the original image is not higher than the entropy
             of the completely blurred image.
          3. If the model prediction on the original image is lower than
             `min_pred_value`.
          If the error is raised, skip the image.
      """
      if img.dtype.type != np.uint8:
          raise ValueError(
              "The `img` array that holds the input image should be of"
              " type uint8. The actual type is {}.".format(img.dtype)
          )
      blurred_images = []
      predictions = []
  
      # This list will contain mapping of image entropy for a given saliency
      # threshold to model prediction.
      entropy_pred_tuples = []
  
      # Estimate entropy of the original image.
      original_img_entropy = estimate_image_entropy(img)
  
      # Estimate entropy of the completely blurred image.
      fully_blurred_img = create_blurred_image(
          full_img=img, pixel_mask=random_mask
      )
      fully_blurred_img_entropy = estimate_image_entropy(
          fully_blurred_img
      )
  
      # Compute model prediction for the original image.
      original_img_pred = pred_func(img[np.newaxis, ...])[0]
  
      if original_img_pred < min_pred_value:
          message = (
              "The model prediction score on the original image is lower than"
              " `min_pred_value`. Skip this image or decrease the"
              " value of `min_pred_value` argument. min_pred_value"
              " = {}, the image prediction"
              " = {}.".format(min_pred_value, original_img_pred)
          )
          raise ComputePicMetricError(message)
  
      # Compute model prediction for the completely blurred image.
      fully_blurred_img_pred = pred_func(
          fully_blurred_img[np.newaxis, ...]
      )[0]
  
      blurred_images.append(fully_blurred_img)
      predictions.append(fully_blurred_img_pred)
  
      # If the entropy of the completely blurred image is higher or equal to the
      # entropy of the original image then the metric cannot be used for this
      # image. Don't include this image in the aggregated result.
      if fully_blurred_img_entropy >= original_img_entropy:
          message = (
              "The entropy in the completely blurred image is not lower than"
              " the entropy in the original image. Catch the error and exclude this"
              " image from evaluation. Blurred entropy: {}, original"
              " entropy {}".format(
                  fully_blurred_img_entropy, original_img_entropy
              )
          )
          raise ComputePicMetricError(message)
  
      # If the score of the model on completely blurred image is higher or equal to
      # the score of the model on the original image then the metric cannot be used
      # for this image. Don't include this image in the aggregated result.
      if fully_blurred_img_pred >= original_img_pred:
          message = (
              "The model prediction score on the completely blurred image is not"
              " lower than the score on the original image. Catch the error and"
              " exclude this image from the evaluation. Blurred score: {}, original"
              " score {}".format(
                  fully_blurred_img_pred, original_img_pred
              )
          )
          raise ComputePicMetricError(message)
  
      # Iterate through saliency thresholds and compute prediction of the model
      # for the corresponding blurred images with the saliency pixels revealed.
      max_normalized_pred = 0.0
      for threshold in saliency_thresholds:
          quantile = np.quantile(saliency_map, 1 - threshold)
          pixel_mask = saliency_map >= quantile
          pixel_mask = np.logical_or(pixel_mask, random_mask)
          blurred_image = create_blurred_image(
              full_img=img, pixel_mask=pixel_mask
          )
          entropy = estimate_image_entropy(blurred_image)
          pred = pred_func(blurred_image[np.newaxis, ...])[0]
          # Normalize the values, so they lie in [0, 1] interval.
          normalized_entropy = (entropy - fully_blurred_img_entropy) / (
              original_img_entropy - fully_blurred_img_entropy
          )
          normalized_entropy = np.clip(normalized_entropy, 0.0, 1.0)
          normalized_pred = (pred - fully_blurred_img_pred) / (
              original_img_pred - fully_blurred_img_pred
          )
          normalized_pred = np.clip(normalized_pred, 0.0, 1.0)
          max_normalized_pred = max(
              max_normalized_pred, normalized_pred
          )
  
          # Make normalized_pred only grow if keep_monotonous is true.
          if keep_monotonous:
              entropy_pred_tuples.append(
                  (normalized_entropy, max_normalized_pred)
              )
          else:
              entropy_pred_tuples.append(
                  (normalized_entropy, normalized_pred)
              )
  
          blurred_images.append(blurred_image)
          predictions.append(pred)
  
      # Interpolate the PIC curve.
      entropy_pred_tuples.append((0.0, 0.0))
      entropy_pred_tuples.append((1.0, 1.0))
  
      entropy_data, pred_data = zip(*entropy_pred_tuples)
      interp_func = interpolate.interp1d(x=entropy_data, y=pred_data)
  
      curve_x = np.linspace(
          start=0.0, stop=1.0, num=num_data_points, endpoint=False
      )
      curve_y = np.asarray([interp_func(x) for x in curve_x])
  
      curve_x = np.append(curve_x, 1.0)
      curve_y = np.append(curve_y, 1.0)
  
      auc = np.trapz(curve_y, curve_x)
  
      blurred_images.append(img)
      predictions.append(original_img_pred)
  
      thresholds = [0.0] + list(saliency_thresholds) + [1.0]
  
      return PicMetricResult(
          curve_x=curve_x,
          curve_y=curve_y,
          blurred_images=blurred_images,
          predictions=predictions,
          thresholds=thresholds,
          auc=auc,
      )
  
file_path: saliency/saliency/metrics/pic.py
imports: import io
  import numpy
  import os
  from PIL import Image
  from scipy import interpolate
  from typing import Callable, List, NamedTuple, Optional, Sequence, Tuple
label_desc: Use image node_id 4 for calling a global function with example usage: compute_pic_metric(img, saliency_map, random_mask, pred_func, saliency_thresholds, min_pred_value, keep_monotonous, num_data_points) and returns: PicMetricResult