text: # Copyright (c) SenseTime. All Rights Reserved.
  
  from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from __future__ import unicode_literals
  
  import cv2
  import numpy as np
  import torch
  
  from pysot.core.config import cfg
  
  
  class BaseTracker(object):
      """ Base tracker of single objec tracking
      """
      def init(self, img, bbox):
          """
          args:
              img(np.ndarray): BGR image
              bbox(list): [x, y, width, height]
                          x, y need to be 0-based
          """
          raise NotImplementedError
  
      def track(self, img):
          """
          args:
              img(np.ndarray): BGR image
          return:
              bbox(list):[x, y, width, height]
          """
          raise NotImplementedError
  
  
  class SiameseTracker(BaseTracker):
      def get_subwindow(self, im, pos, model_sz, original_sz, avg_chans):
          """
          args:  按照original_sz从img中扣取感兴趣区域，并resize到model_sz大小
              im: bgr based image
              pos: center position,模板在原图中的中心坐标
              model_sz: exemplar size
              s_z: original size
              avg_chans: channel average
          """
          if isinstance(pos, float):
              pos = [pos, pos]
          sz = original_sz
          im_sz = im.shape
          c = (original_sz + 1) / 2
          # context_xmin = round(pos[0] - c) # py2 and py3 round
          context_xmin = np.floor(pos[0] - c + 0.5)
          context_xmax = context_xmin + sz - 1
          # context_ymin = round(pos[1] - c)
          context_ymin = np.floor(pos[1] - c + 0.5)
          context_ymax = context_ymin + sz - 1
          left_pad = int(max(0., -context_xmin))
          top_pad = int(max(0., -context_ymin))
          right_pad = int(max(0., context_xmax - im_sz[1] + 1))
          bottom_pad = int(max(0., context_ymax - im_sz[0] + 1))
  
          context_xmin = context_xmin + left_pad       #如果超出图像边界外，加上padding后的坐标
          context_xmax = context_xmax + left_pad
          context_ymin = context_ymin + top_pad
          context_ymax = context_ymax + top_pad
  
          r, c, k = im.shape
          if any([top_pad, bottom_pad, left_pad, right_pad]):         #如果存在padding，则将padding 加上去
  
              #如果需要padding，则先生成一个全0的大图，再将图像填充到对应位置，最后将padding区域填补为图像均值
              size = (r + top_pad + bottom_pad, c + left_pad + right_pad, k)
              te_im = np.zeros(size, np.uint8)
              #将图像填充到对应位置
              te_im[top_pad:top_pad + r, left_pad:left_pad + c, :] = im
              #将padding区域填补为图像均值
              if top_pad:
                  te_im[0:top_pad, left_pad:left_pad + c, :] = avg_chans
              if bottom_pad:
                  te_im[r + top_pad:, left_pad:left_pad + c, :] = avg_chans
              if left_pad:
                  te_im[:, 0:left_pad, :] = avg_chans
              if right_pad:
                  te_im[:, c + left_pad:, :] = avg_chans
  
              #从padding之后的大图中裁剪需要的图像块
              im_patch = te_im[int(context_ymin):int(context_ymax + 1),
                               int(context_xmin):int(context_xmax + 1), :]
          else:
              im_patch = im[int(context_ymin):int(context_ymax + 1),
                            int(context_xmin):int(context_xmax + 1), :]
  
          if not np.array_equal(model_sz, original_sz):               #将目标区域缩放到设定的模板分支大小
              im_patch = cv2.resize(im_patch, (model_sz, model_sz))
          im_patch = im_patch.transpose(2, 0, 1)              #bgr-->rgb
          im_patch = im_patch[np.newaxis, :, :, :]            #[c,h,w]-->[1,c,h,w]
          im_patch = im_patch.astype(np.float32)
          im_patch = torch.from_numpy(im_patch)
          if cfg.CUDA:
              im_patch = im_patch.cuda()
          return im_patch
  