code: def apply_transformation(
      x: np.ndarray,
      mask: np.ndarray,
      pert: np.ndarray,
      angle: float,
      dist: float,
      gamma: float,
      blur: int,
      crop_percent: float,
      crop_off_x: float,
      crop_off_y: float,
      net_size: Tuple[int, int],
      obj_width: float,
      focal: float,
      clip_min: float,
      clip_max: float,
      pts: Optional[np.ndarray] = None,
  ) -> np.ndarray:
      """
      Apply transformation to input image.
  
      :param x: Input image.
      :param mask: Input mask.
      :param pert: Input perturbation.
      :param angle: Angle to rotate image.
      :param dist: Distance in ft for perspective transform.
      :param gamma: Factor for gamma transform.
      :param blur: Kernel width for blurring.
      :param crop_percent: Percent to crop image at.
      :param crop_off_x: x offset for crop.
      :param crop_off_y: y offset for crop.
      :param net_size: Size of the image for the network.
      :param obj_width: Estimated width of object in inches for perspective transform.
      :param focal: Estimated focal length in ft for perspective transform.
      :param clip_min: Minimum value of an example.
      :param clip_max: Maximum value of an example.
      :param pts: A set of points that will set the crop size in the perspective transform.
      :return: Transformed image in network form.
      """
      import cv2
  
      if blur != 0:
          pert = cv2.GaussianBlur(pert, (blur, blur), 0)
  
      if len(pert.shape) < 3:
          pert = pert[:, :, np.newaxis]
  
      att = np.where(mask > 0.5, pert, x)
      att = np.clip(att, 0.0, 1.0)
  
      dist = dist2pixels(dist, att.shape[1], obj_width)
      focal = dist2pixels(focal, att.shape[1], obj_width)
      att = get_perspective_transform(
          att,
          angle,
          att.shape[1],
          att.shape[0],
          focal,
          dist,
          crop_percent,
          crop_off_x,
          crop_off_y,
          pts,
      )
  
      if len(att.shape) < 3:
          att = att[:, :, np.newaxis]
  
      # Gamma
      att_uint = (att * 255.0).astype(np.uint8)
      table = np.empty((256), np.uint8)
      for i in range(256):
          table[i] = np.clip(pow(i / 255.0, gamma) * 255.0, 0, 255)
      att_uint = cv2.LUT(att_uint, table)  # type: ignore
      att = (att_uint / 255.0).astype(np.float32)
      att = np.clip(att, 0.0, 1.0)
  
      return convert_to_network(att, net_size, clip_min, clip_max)
  
imports: from typing import Optional, Tuple, Union, TYPE_CHECKING, List
  import math
  import numpy
  from art.estimators.estimator import BaseEstimator
  from art.estimators.classification import ClassifierMixin
  from art.utils import get_labels_np_array
label_desc: Use image node_id 3 for calling a global function with example usage: apply_transformation(x, mask, pert, angle, dist, gamma, blur, crop_percent, crop_off_x, crop_off_y, net_size, obj_width, focal, clip_min, clip_max, pts) and returns: convert_to_network