# -------------------------------------------------------- # SiamMask # Licensed under The MIT License # Written by Qiang Wang (wangqiang2015 at ia.ac.cn) # -------------------------------------------------------- import numpy as np from collections import namedtuple Corner = namedtuple('Corner', 'x1 y1 x2 y2') BBox = Corner Center = namedtuple('Center', 'x y w h') def corner2center(corner): """ :param corner: Corner or np.array 4*N :return: Center or 4 np.array N """ if isinstance(corner, Corner): x1, y1, x2, y2 = corner return Center((x1 + x2) * 0.5, (y1 + y2) * 0.5, (x2 - x1), (y2 - y1)) else: x1, y1, x2, y2 = corner[0], corner[1], corner[2], corner[3] x = (x1 + x2) * 0.5 y = (y1 + y2) * 0.5 w = x2 - x1 h = y2 - y1 return x, y, w, h def center2corner(center): """ :param center: Center or np.array 4*N :return: Corner or np.array 4*N """ if isinstance(center, Center): x, y, w, h = center return Corner(x - w * 0.5, y - h * 0.5, x + w * 0.5, y + h * 0.5) else: x, y, w, h = center[0], center[1], center[2], center[3] x1 = x - w * 0.5 y1 = y - h * 0.5 x2 = x + w * 0.5 y2 = y + h * 0.5 return x1, y1, x2, y2 def cxy_wh_2_rect(pos, sz): return np.array([pos[0]-sz[0]/2, pos[1]-sz[1]/2, sz[0], sz[1]]) # 0-index def get_axis_aligned_bbox(region): nv = region.size if nv == 8: cx = np.mean(region[0::2]) cy = np.mean(region[1::2]) x1 = min(region[0::2]) x2 = max(region[0::2]) y1 = min(region[1::2]) y2 = max(region[1::2]) A1 = np.linalg.norm(region[0:2] - region[2:4]) * np.linalg.norm(region[2:4] - region[4:6]) A2 = (x2 - x1) * (y2 - y1) s = np.sqrt(A1 / A2) w = s * (x2 - x1) + 1 h = s * (y2 - y1) + 1 else: x = region[0] y = region[1] w = region[2] h = region[3] cx = x+w/2 cy = y+h/2 return cx, cy, w, h def aug_apply(bbox, param, shape, inv=False, rd=False): """ apply augmentation :param bbox: original bbox in image :param param: augmentation param, shift/scale :param shape: image shape, h, w, (c) :param inv: inverse :param rd: round bbox :return: bbox(, param) bbox: augmented bbox param: real augmentation param """ if not inv: center = corner2center(bbox) original_center = center real_param = {} if 'scale' in param: scale_x, scale_y = param['scale'] imh, imw = shape[:2] h, w = center.h, center.w scale_x = min(scale_x, float(imw) / w) scale_y = min(scale_y, float(imh) / h) # center.w *= scale_x # center.h *= scale_y center = Center(center.x, center.y, center.w * scale_x, center.h * scale_y) bbox = center2corner(center) if 'shift' in param: tx, ty = param['shift'] x1, y1, x2, y2 = bbox imh, imw = shape[:2] tx = max(-x1, min(imw - 1 - x2, tx)) ty = max(-y1, min(imh - 1 - y2, ty)) bbox = Corner(x1 + tx, y1 + ty, x2 + tx, y2 + ty) if rd: bbox = Corner(*map(round, bbox)) current_center = corner2center(bbox) real_param['scale'] = current_center.w / original_center.w, current_center.h / original_center.h real_param['shift'] = current_center.x - original_center.x, current_center.y - original_center.y return bbox, real_param else: if 'scale' in param: scale_x, scale_y = param['scale'] else: scale_x, scale_y = 1., 1. if 'shift' in param: tx, ty = param['shift'] else: tx, ty = 0, 0 center = corner2center(bbox) center = Center(center.x - tx, center.y - ty, center.w / scale_x, center.h / scale_y) return center2corner(center) def IoU(rect1, rect2): # overlap x1, y1, x2, y2 = rect1[0], rect1[1], rect1[2], rect1[3] tx1, ty1, tx2, ty2 = rect2[0], rect2[1], rect2[2], rect2[3] xx1 = np.maximum(tx1, x1) yy1 = np.maximum(ty1, y1) xx2 = np.minimum(tx2, x2) yy2 = np.minimum(ty2, y2) ww = np.maximum(0, xx2 - xx1) hh = np.maximum(0, yy2 - yy1) area = (x2-x1) * (y2-y1) target_a = (tx2-tx1) * (ty2 - ty1) inter = ww * hh overlap = inter / (area + target_a - inter) return overlap