text: import tensorflow as tf
  import math
  import tensorflow.keras.backend as K
  from config.load_config import config
  
  
  def get_mat(rotation, shear, height_zoom, width_zoom, height_shift, width_shift):
      # returns 3x3 transformmatrix which transforms indicies
  
      # CONVERT DEGREES TO RADIANS
      rotation = math.pi * rotation / 180.0
      shear = math.pi * shear / 180.0
  
      def get_3x3_mat(lst):
          return tf.reshape(tf.concat([lst], axis=0), [3, 3])
  
      # ROTATION MATRIX
      c1 = tf.math.cos(rotation)
      s1 = tf.math.sin(rotation)
      one = tf.constant([1], dtype="float32")
      zero = tf.constant([0], dtype="float32")
  
      rotation_matrix = get_3x3_mat([c1, s1, zero, -s1, c1, zero, zero, zero, one])
      # SHEAR MATRIX
      c2 = tf.math.cos(shear)
      s2 = tf.math.sin(shear)
  
      shear_matrix = get_3x3_mat([one, s2, zero, zero, c2, zero, zero, zero, one])
      # ZOOM MATRIX
      zoom_matrix = get_3x3_mat(
          [one / height_zoom, zero, zero, zero, one / width_zoom, zero, zero, zero, one]
      )
      # SHIFT MATRIX
      shift_matrix = get_3x3_mat([one, zero, height_shift, zero, one, width_shift, zero, zero, one])
  
      return K.dot(K.dot(rotation_matrix, shear_matrix), K.dot(zoom_matrix, shift_matrix))
  
  
  # config is the config dict from load_config yaml
  def transform(image, config):
      # input image - is one image of size [dim,dim,3] not a batch of [b,dim,dim,3]
      # output - image randomly rotated, sheared, zoomed, and shifted
      DIM = config["IMG_SIZES"]
      XDIM = DIM % 2  # fix for size 331
  
      rot = config["ROT_"] * tf.random.normal([1], dtype="float32")
      shr = config["SHR_"] * tf.random.normal([1], dtype="float32")
      h_zoom = 1.0 + tf.random.normal([1], dtype="float32") / config["HZOOM_"]
      w_zoom = 1.0 + tf.random.normal([1], dtype="float32") / config["WZOOM_"]
      h_shift = config["HSHIFT_"] * tf.random.normal([1], dtype="float32")
      w_shift = config["WSHIFT_"] * tf.random.normal([1], dtype="float32")
  
      # GET TRANSFORMATION MATRIX
      m = get_mat(rot, shr, h_zoom, w_zoom, h_shift, w_shift)
  
      # LIST DESTINATION PIXEL INDICES
      x = tf.repeat(tf.range(DIM // 2, -DIM // 2, -1), DIM)
      y = tf.tile(tf.range(-DIM // 2, DIM // 2), [DIM])
      z = tf.ones([DIM * DIM], dtype="int32")
      idx = tf.stack([x, y, z])
  
      # ROTATE DESTINATION PIXELS ONTO ORIGIN PIXELS
      idx2 = K.dot(m, tf.cast(idx, dtype="float32"))
      idx2 = K.cast(idx2, dtype="int32")
      idx2 = K.clip(idx2, -DIM // 2 + XDIM + 1, DIM // 2)
  
      # FIND ORIGIN PIXEL VALUES
      idx3 = tf.stack([DIM // 2 - idx2[0,], DIM // 2 - 1 + idx2[1,]])
      d = tf.gather_nd(image, tf.transpose(idx3))
  
      return tf.reshape(d, [DIM, DIM, 3])
  
  