text: #!/usr/bin/env python3
  # -*- coding: utf-8 -*-
  
  import time
  import numpy as np
  
  def IoU(box, boxes):
      """Compute IoU between detect box and gt boxes
  
      Parameters:
      ---------·-
      box: numpy array , shape (5, ): x1, y1, x2, y2, score
          input box
      boxes: numpy array, shape (n, 4): x1, y1, x2, y2
          input ground truth boxes
  
      Returns:
      -------
      ovr: numpy.array, shape (n, )
          IoU
      """
      box_area = (box[2] - box[0] + 1) * (box[3] - box[1] + 1)
      area = (boxes[:, 2] - boxes[:, 0] + 1) * (boxes[:, 3] - boxes[:, 1] + 1)
      xx1 = np.maximum(box[0], boxes[:, 0])
      yy1 = np.maximum(box[1], boxes[:, 1])
      xx2 = np.minimum(box[2], boxes[:, 2])
      yy2 = np.minimum(box[3], boxes[:, 3])
  
      # compute the width and height of the bounding box
      w = np.maximum(0, xx2 - xx1 + 1)
      h = np.maximum(0, yy2 - yy1 + 1)
  
      inter = w * h
      ovr = np.true_divide(inter,(box_area + area - inter))
      #ovr = inter / (box_area + area - inter)
      return ovr
  
  
  def convert_to_square(bbox):
      """Convert bbox to square
  
      Parameters:
      ----------
      bbox: numpy array , shape n x 5
          input bbox
  
      Returns:
      -------
      square bbox
      """
      square_bbox = bbox.copy()
  
      h = bbox[:, 3] - bbox[:, 1] + 1
      w = bbox[:, 2] - bbox[:, 0] + 1
      max_side = np.maximum(h, w)
      square_bbox[:, 0] = bbox[:, 0] + (w - max_side) * 0.5
      square_bbox[:, 1] = bbox[:, 1] + (h - max_side) * 0.5
      square_bbox[:, 2] = square_bbox[:, 0] + max_side - 1
      square_bbox[:, 3] = square_bbox[:, 1] + max_side - 1
      return square_bbox
  
  
  def nms(dets, thresh, mode = 'Union'):
  
      x1, y1 = dets[:, 0], dets[:, 1]
      x2, y2 = dets[:, 2], dets[:, 3]
      order  = dets[:, 4].argsort()[::-1]  # descending order
      areas  = (x2 - x1 + 1) * (y2 - y1 + 1)
  
      keep = []
      while order.size > 0:
  
          i = order[0]
          keep.append(i)
          xx1 = np.maximum(x1[i], x1[order[1:]])
          yy1 = np.maximum(y1[i], y1[order[1:]])
          xx2 = np.minimum(x2[i], x2[order[1:]])
          yy2 = np.minimum(y2[i], y2[order[1:]])
  
          w = np.maximum(0.0, xx2 - xx1 + 1)
          h = np.maximum(0.0, yy2 - yy1 + 1)
          inter = w * h
  
          if mode == 'Union':
              ovr = inter / (areas[i] + areas[order[1:]] - inter)
          elif mode == 'Minimum':
              ovr = inter / np.minimum(areas[i], areas[order[1:]])
  
          inds = np.where(ovr <= thresh)[0]
          order = order[inds + 1] # +1: eliminates the first element in order
  
      return keep
  