text: import os
  
  import torch, cv2
  import random
  import numpy as np
  
  
  def tens2image(im):
      if im.size()[0] == 1:
          tmp = np.squeeze(im.numpy(), axis=0)
      else:
          tmp = im.numpy()
      if tmp.ndim == 2:
          return tmp
      else:
          return tmp.transpose((1, 2, 0))
  
  
  def crop2fullmask(crop_mask, bbox, im=None, im_size=None, zero_pad=False, relax=0, mask_relax=True,
                    interpolation=cv2.INTER_CUBIC, scikit=False):
      if scikit:
          from skimage.transform import resize as sk_resize
      assert(not(im is None and im_size is None)), 'You have to provide an image or the image size'
      if im is None:
          im_si = im_size
      else:
          im_si = im.shape
      # Borers of image
      bounds = (0, 0, im_si[1] - 1, im_si[0] - 1)
  
      # Valid bounding box locations as (x_min, y_min, x_max, y_max)
      bbox_valid = (max(bbox[0], bounds[0]),
                    max(bbox[1], bounds[1]),
                    min(bbox[2], bounds[2]),
                    min(bbox[3], bounds[3]))
  
      # Bounding box of initial mask
      bbox_init = (bbox[0] + relax,
                   bbox[1] + relax,
                   bbox[2] - relax,
                   bbox[3] - relax)
  
      if zero_pad:
          # Offsets for x and y
          offsets = (-bbox[0], -bbox[1])
      else:
          assert((bbox == bbox_valid).all())
          offsets = (-bbox_valid[0], -bbox_valid[1])
  
      # Simple per element addition in the tuple
      inds = tuple(map(sum, zip(bbox_valid, offsets + offsets)))
  
      if scikit:
          crop_mask = sk_resize(crop_mask, (bbox[3] - bbox[1] + 1, bbox[2] - bbox[0] + 1), order=0, mode='constant').astype(crop_mask.dtype)
      else:
          crop_mask = cv2.resize(crop_mask, (bbox[2] - bbox[0] + 1, bbox[3] - bbox[1] + 1), interpolation=interpolation)
      result_ = np.zeros(im_si)
      result_[bbox_valid[1]:bbox_valid[3] + 1, bbox_valid[0]:bbox_valid[2] + 1] = \
          crop_mask[inds[1]:inds[3] + 1, inds[0]:inds[2] + 1]
  
      result = np.zeros(im_si)
      if mask_relax:
          result[bbox_init[1]:bbox_init[3]+1, bbox_init[0]:bbox_init[2]+1] = \
              result_[bbox_init[1]:bbox_init[3]+1, bbox_init[0]:bbox_init[2]+1]
      else:
          result = result_
  
      return result
  
  
  def overlay_mask(im, ma, colors=None, alpha=0.5):
      assert np.max(im) <= 1.0
      if colors is None:
          colors = np.load(os.path.join(os.path.dirname(__file__), 'pascal_map.npy'))/255.
      else:
          colors = np.append([[0.,0.,0.]], colors, axis=0);
  
      if ma.ndim == 3:
          assert len(colors) >= ma.shape[0], 'Not enough colors'
      ma = ma.astype(np.bool)
      im = im.astype(np.float32)
  
      if ma.ndim == 2:
          fg = im * alpha+np.ones(im.shape) * (1 - alpha) * colors[1, :3]   # np.array([0,0,255])/255.0
      else:
          fg = []
          for n in range(ma.ndim):
              fg.append(im * alpha + np.ones(im.shape) * (1 - alpha) * colors[1+n, :3])
      # Whiten background
      bg = im.copy()
      if ma.ndim == 2:
          bg[ma == 0] = im[ma == 0]
          bg[ma == 1] = fg[ma == 1]
          total_ma = ma
      else:
          total_ma = np.zeros([ma.shape[1], ma.shape[2]])
          for n in range(ma.shape[0]):
              tmp_ma = ma[n, :, :]
              total_ma = np.logical_or(tmp_ma, total_ma)
              tmp_fg = fg[n]
              bg[tmp_ma == 1] = tmp_fg[tmp_ma == 1]
          bg[total_ma == 0] = im[total_ma == 0]
  
      # [-2:] is s trick to be compatible both with opencv 2 and 3
      contours = cv2.findContours(total_ma.copy().astype(np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[-2:]
      cv2.drawContours(bg, contours[0], -1, (0.0, 0.0, 0.0), 1)
  
      return bg
  
  def overlay_masks(im, masks, alpha=0.5):
      colors = np.load(os.path.join(os.path.dirname(__file__), 'pascal_map.npy'))/255.
      
      if isinstance(masks, np.ndarray):
          masks = [masks]
  
      assert len(colors) >= len(masks), 'Not enough colors'
  
      ov = im.copy()
      im = im.astype(np.float32)
      total_ma = np.zeros([im.shape[0], im.shape[1]])
      i = 1
      for ma in masks:
          ma = ma.astype(np.bool)
          fg = im * alpha+np.ones(im.shape) * (1 - alpha) * colors[i, :3]   # np.array([0,0,255])/255.0
          i = i + 1
          ov[ma == 1] = fg[ma == 1]
          total_ma += ma
  
          # [-2:] is s trick to be compatible both with opencv 2 and 3
          contours = cv2.findContours(ma.copy().astype(np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[-2:]
          cv2.drawContours(ov, contours[0], -1, (0.0, 0.0, 0.0), 1)
      ov[total_ma == 0] = im[total_ma == 0]
  
      return ov
  
  
  def extreme_points(mask, pert):
      def find_point(id_x, id_y, ids):
          sel_id = ids[0][random.randint(0, len(ids[0]) - 1)]
          return [id_x[sel_id], id_y[sel_id]]
  
      # List of coordinates of the mask
      inds_y, inds_x = np.where(mask > 0.5)
  
      # Find extreme points
      return np.array([find_point(inds_x, inds_y, np.where(inds_x <= np.min(inds_x)+pert)), # left
                       find_point(inds_x, inds_y, np.where(inds_x >= np.max(inds_x)-pert)), # right
                       find_point(inds_x, inds_y, np.where(inds_y <= np.min(inds_y)+pert)), # top
                       find_point(inds_x, inds_y, np.where(inds_y >= np.max(inds_y)-pert)) # bottom
                       ])
  
  
  def get_bbox(mask, points=None, pad=0, zero_pad=False):
      if points is not None:
          inds = np.flip(points.transpose(), axis=0)
      else:
          inds = np.where(mask > 0)
  
      if inds[0].shape[0] == 0:
          return None
  
      if zero_pad:
          x_min_bound = -np.inf
          y_min_bound = -np.inf
          x_max_bound = np.inf
          y_max_bound = np.inf
      else:
          x_min_bound = 0
          y_min_bound = 0
          x_max_bound = mask.shape[1] - 1
          y_max_bound = mask.shape[0] - 1
  
      x_min = max(inds[1].min() - pad, x_min_bound)
      y_min = max(inds[0].min() - pad, y_min_bound)
      x_max = min(inds[1].max() + pad, x_max_bound)
      y_max = min(inds[0].max() + pad, y_max_bound)
  
      return x_min, y_min, x_max, y_max
  
  
  def crop_from_bbox(img, bbox, zero_pad=False):
      # Borders of image
      bounds = (0, 0, img.shape[1] - 1, img.shape[0] - 1)
  
      # Valid bounding box locations as (x_min, y_min, x_max, y_max)
      bbox_valid = (max(bbox[0], bounds[0]),
                    max(bbox[1], bounds[1]),
                    min(bbox[2], bounds[2]),
                    min(bbox[3], bounds[3]))
  
      if zero_pad:
          # Initialize crop size (first 2 dimensions)
          crop = np.zeros((bbox[3] - bbox[1] + 1, bbox[2] - bbox[0] + 1), dtype=img.dtype)
  
          # Offsets for x and y
          offsets = (-bbox[0], -bbox[1])
  
      else:
          assert(bbox == bbox_valid)
          crop = np.zeros((bbox_valid[3] - bbox_valid[1] + 1, bbox_valid[2] - bbox_valid[0] + 1), dtype=img.dtype)
          offsets = (-bbox_valid[0], -bbox_valid[1])
  
      # Simple per element addition in the tuple
      inds = tuple(map(sum, zip(bbox_valid, offsets + offsets)))
  
      img = np.squeeze(img)
      if img.ndim == 2:
          crop[inds[1]:inds[3] + 1, inds[0]:inds[2] + 1] = \
              img[bbox_valid[1]:bbox_valid[3] + 1, bbox_valid[0]:bbox_valid[2] + 1]
      else:
          crop = np.tile(crop[:, :, np.newaxis], [1, 1, 3])  # Add 3 RGB Channels
          crop[inds[1]:inds[3] + 1, inds[0]:inds[2] + 1, :] = \
              img[bbox_valid[1]:bbox_valid[3] + 1, bbox_valid[0]:bbox_valid[2] + 1, :]
  
      return crop
  
  
  def fixed_resize(sample, resolution, flagval=None):
  
      if flagval is None:
          if ((sample == 0) | (sample == 1)).all():
              flagval = cv2.INTER_NEAREST
          else:
              flagval = cv2.INTER_CUBIC
  
      if isinstance(resolution, int):
          tmp = [resolution, resolution]
          tmp[np.argmax(sample.shape[:2])] = int(round(float(resolution)/np.min(sample.shape[:2])*np.max(sample.shape[:2])))
          resolution = tuple(tmp)
  
      if sample.ndim == 2 or (sample.ndim == 3 and sample.shape[2] == 3):
          sample = cv2.resize(sample, resolution[::-1], interpolation=flagval)
      else:
          tmp = sample
          sample = np.zeros(np.append(resolution, tmp.shape[2]), dtype=np.float32)
          for ii in range(sample.shape[2]):
              sample[:, :, ii] = cv2.resize(tmp[:, :, ii], resolution[::-1], interpolation=flagval)
      return sample
  
  
  def crop_from_mask(img, mask, relax=0, zero_pad=False):
      if mask.shape[:2] != img.shape[:2]:
          mask = cv2.resize(mask, dsize=tuple(reversed(img.shape[:2])), interpolation=cv2.INTER_NEAREST)
  
      assert(mask.shape[:2] == img.shape[:2])
  
      bbox = get_bbox(mask, pad=relax, zero_pad=zero_pad)
  
      if bbox is None:
          return None
  
      crop = crop_from_bbox(img, bbox, zero_pad)
  
      return crop
  
  
  def make_gaussian(size, sigma=10, center=None, d_type=np.float64):
      """ Make a square gaussian kernel.
      size: is the dimensions of the output gaussian
      sigma: is full-width-half-maximum, which
      can be thought of as an effective radius.
      """
  
      x = np.arange(0, size[1], 1, float)
      y = np.arange(0, size[0], 1, float)
      y = y[:, np.newaxis]
  
      if center is None:
          x0 = y0 = size[0] // 2
      else:
          x0 = center[0]
          y0 = center[1]
  
      return np.exp(-4 * np.log(2) * ((x - x0) ** 2 + (y - y0) ** 2) / sigma ** 2).astype(d_type)
  
  
  def make_gt(img, labels, sigma=10, one_mask_per_point=False):
      """ Make the ground-truth for  landmark.
      img: the original color image
      labels: label with the Gaussian center(s) [[x0, y0],[x1, y1],...]
      sigma: sigma of the Gaussian.
      one_mask_per_point: masks for each point in different channels?
      """
      h, w = img.shape[:2]
      if labels is None:
          gt = make_gaussian((h, w), center=(h//2, w//2), sigma=sigma)
      else:
          labels = np.array(labels)
          if labels.ndim == 1:
              labels = labels[np.newaxis]
          if one_mask_per_point:
              gt = np.zeros(shape=(h, w, labels.shape[0]))
              for ii in range(labels.shape[0]):
                  gt[:, :, ii] = make_gaussian((h, w), center=labels[ii, :], sigma=sigma)
          else:
              gt = np.zeros(shape=(h, w), dtype=np.float64)
              for ii in range(labels.shape[0]):
                  gt = np.maximum(gt, make_gaussian((h, w), center=labels[ii, :], sigma=sigma))
  
      gt = gt.astype(dtype=img.dtype)
  
      return gt
  
  
  def cstm_normalize(im, max_value):
      """
      Normalize image to range 0 - max_value
      """
      imn = max_value*(im - im.min()) / max((im.max() - im.min()), 1e-8)
      return imn
  
  
  def generate_param_report(logfile, param):
      log_file = open(logfile, 'w')
      for key, val in param.items():
          log_file.write(key+':'+str(val)+'\n')
      log_file.close()
  