text: # ------------------------------------------------------------------------------
  # Copyright (c) Microsoft
  # Licensed under the MIT License.
  # Modified from py-faster-rcnn (https://github.com/rbgirshick/py-faster-rcnn)
  # ------------------------------------------------------------------------------
  
  from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  
  import numpy as np
  
  import pyximport
  pyximport.install()
  
  from .cpu_nms import cpu_nms
  from .gpu_nms import gpu_nms
  
  
  def py_nms_wrapper(thresh):
      def _nms(dets):
          return nms(dets, thresh)
      return _nms
  
  
  def cpu_nms_wrapper(thresh):
      def _nms(dets):
          return cpu_nms(dets, thresh)
      return _nms
  
  
  def gpu_nms_wrapper(thresh, device_id):
      def _nms(dets):
          return gpu_nms(dets, thresh, device_id)
      return _nms
  
  
  def nms(dets, thresh):
      """
      greedily select boxes with high confidence and overlap with current maximum <= thresh
      rule out overlap >= thresh
      :param dets: [[x1, y1, x2, y2 score]]
      :param thresh: retain overlap < thresh
      :return: indexes to keep
      """
      if dets.shape[0] == 0:
          return []
  
      x1 = dets[:, 0]
      y1 = dets[:, 1]
      x2 = dets[:, 2]
      y2 = dets[:, 3]
      scores = dets[:, 4]
  
      areas = (x2 - x1 + 1) * (y2 - y1 + 1)
      order = scores.argsort()[::-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
          ovr = inter / (areas[i] + areas[order[1:]] - inter)
  
          inds = np.where(ovr <= thresh)[0]
          order = order[inds + 1]
  
      return keep
  
  def oks_iou(g, d, a_g, a_d, sigmas=None, in_vis_thre=None):
      if not isinstance(sigmas, np.ndarray):
          sigmas = np.array([.26, .25, .25, .35, .35, .79, .79, .72, .72, .62, .62, 1.07, 1.07, .87, .87, .89, .89]) / 10.0
      vars = (sigmas * 2) ** 2
      xg = g[0::3]
      yg = g[1::3]
      vg = g[2::3]
      ious = np.zeros((d.shape[0]))
      for n_d in range(0, d.shape[0]):
          xd = d[n_d, 0::3]
          yd = d[n_d, 1::3]
          vd = d[n_d, 2::3]
          dx = xd - xg
          dy = yd - yg
          e = (dx ** 2 + dy ** 2) / vars / ((a_g + a_d[n_d]) / 2 + np.spacing(1)) / 2
          if in_vis_thre is not None:
              ind = list(vg > in_vis_thre) and list(vd > in_vis_thre)
              e = e[ind]
          ious[n_d] = np.sum(np.exp(-e)) / e.shape[0] if e.shape[0] != 0 else 0.0
      return ious
  
  def oks_nms(kpts_db, thresh, sigmas=None, in_vis_thre=None):
      """
      greedily select boxes with high confidence and overlap with current maximum <= thresh
      rule out overlap >= thresh, overlap = oks
      :param kpts_db
      :param thresh: retain overlap < thresh
      :return: indexes to keep
      """
      if len(kpts_db) == 0:
          return []
  
      scores = np.array([kpts_db[i]['score'] for i in range(len(kpts_db))])
      kpts = np.array([kpts_db[i]['keypoints'].flatten() for i in range(len(kpts_db))])
      areas = np.array([kpts_db[i]['area'] for i in range(len(kpts_db))])
  
      order = scores.argsort()[::-1]
  
      keep = []
      while order.size > 0:
          i = order[0]
          keep.append(i)
  
          oks_ovr = oks_iou(kpts[i], kpts[order[1:]], areas[i], areas[order[1:]], sigmas, in_vis_thre)
  
          inds = np.where(oks_ovr <= thresh)[0]
          order = order[inds + 1]
  
      return keep
  
  