import numbers import numpy as np LIMIT = 99999999 def clip_bbox(bboxes, min_clip, max_x_clip, max_y_clip): ''' # BBoxes are [x1, y1, x2, y2] ''' bboxes_out = bboxes added_axis = False if len(bboxes_out.shape) == 1: added_axis = True bboxes_out = bboxes_out[:, np.newaxis] bboxes_out[[0, 2], ...] = np.clip(bboxes_out[[0, 2], ...], min_clip, max_x_clip) bboxes_out[[1, 3], ...] = np.clip(bboxes_out[[1, 3], ...], min_clip, max_y_clip) if added_axis: bboxes_out = bboxes_out[:, 0] return bboxes_out def xyxy_to_xywh(bboxes, clip_min=-LIMIT, clip_width=LIMIT, clip_height=LIMIT, round=False): ''' [x1 y1, x2, y2] to [xMid, yMid, width, height] ''' added_axis = False if isinstance(bboxes, list): bboxes = np.array(bboxes).astype(np.float32) if len(bboxes.shape) == 1: added_axis = True bboxes = bboxes[:, np.newaxis] bboxes_out = np.zeros(bboxes.shape) x1 = bboxes[0, ...] y1 = bboxes[1, ...] x2 = bboxes[2, ...] y2 = bboxes[3, ...] bboxes_out[0, ...] = (x1 + x2) / 2.0 bboxes_out[1, ...] = (y1 + y2) / 2.0 bboxes_out[2, ...] = x2 - x1 bboxes_out[3, ...] = y2 - y1 if clip_min != -LIMIT or clip_width != LIMIT or clip_height != LIMIT: bboxes_out = clip_bbox(bboxes_out, clip_min, clip_width, clip_height) if bboxes_out.shape[0] > 4: bboxes_out[4:, ...] = bboxes[4:, ...] if added_axis: bboxes_out = bboxes_out[:, 0] if round: bboxes_out = np.round(bboxes_out).astype(int) return bboxes_out def xywh_to_xyxy(bboxes, clip_min=-LIMIT, clip_width=LIMIT, clip_height=LIMIT, round=False): ''' [xMid, yMid, width, height] to [x1 y1, x2, y2] ''' added_axis = False if isinstance(bboxes, list): bboxes = np.array(bboxes).astype(np.float32) if len(bboxes.shape) == 1: added_axis = True bboxes = bboxes[:, np.newaxis] bboxes_out = np.zeros(bboxes.shape) x_mid = bboxes[0, ...] y_mid = bboxes[1, ...] width = bboxes[2, ...] height = bboxes[3, ...] bboxes_out[0, ...] = x_mid - width / 2.0 bboxes_out[1, ...] = y_mid - height / 2.0 bboxes_out[2, ...] = x_mid + width / 2.0 bboxes_out[3, ...] = y_mid + height / 2.0 if clip_min != -LIMIT or clip_width != LIMIT or clip_height != LIMIT: bboxes_out = clip_bbox(bboxes_out, clip_min, clip_width, clip_height) if bboxes_out.shape[0] > 4: bboxes_out[4:, ...] = bboxes[4:, ...] if added_axis: bboxes_out = bboxes_out[:, 0] if round: bboxes_out = np.round(bboxes_out).astype(int) return bboxes_out def scale_bbox(bboxes, scalars, clip_min=-LIMIT, clip_width=LIMIT, clip_height=LIMIT, round=False, in_place=False): ''' @bboxes {np.array} 4xn array of boxes to be scaled @scalars{number or arraylike} scalars for width and height of boxes @in_place{bool} If false, creates new bboxes. ''' added_axis = False if isinstance(bboxes, list): bboxes = np.array(bboxes, dtype=np.float32) if len(bboxes.shape) == 1: added_axis = True bboxes = bboxes[:, np.newaxis] if isinstance(scalars, numbers.Number): scalars = np.full((2, bboxes.shape[1]), scalars, dtype=np.float32) if not isinstance(scalars, np.ndarray): scalars = np.array(scalars, dtype=np.float32) if len(scalars.shape) == 1: scalars = np.tile(scalars[:, np.newaxis], (1, bboxes.shape[1])) width = bboxes[2, ...] - bboxes[0, ...] height = bboxes[3, ...] - bboxes[1, ...] x_mid = (bboxes[0, ...] + bboxes[2, ...]) / 2.0 y_mid = (bboxes[1, ...] + bboxes[3, ...]) / 2.0 if not in_place: bboxes_out = bboxes.copy() else: bboxes_out = bboxes bboxes_out[0, ...] = x_mid - width * scalars[0, ...] / 2.0 bboxes_out[1, ...] = y_mid - height * scalars[1, ...] / 2.0 bboxes_out[2, ...] = x_mid + width * scalars[0, ...] / 2.0 bboxes_out[3, ...] = y_mid + height * scalars[1, ...] / 2.0 if clip_min != -LIMIT or clip_width != LIMIT or clip_height != LIMIT: bboxes_out = clip_bbox(bboxes_out, clip_min, clip_width, clip_height) if added_axis: bboxes_out = bboxes_out[:, 0] if round: bboxes_out = np.round(bboxes_out).astype(int) return bboxes_out def make_square(bboxes, in_place=False): if isinstance(bboxes, list): bboxes = np.array(bboxes).astype(np.float32) if len(bboxes.shape) == 1: num_boxes = 1 width = bboxes[2] - bboxes[0] height = bboxes[3] - bboxes[1] else: num_boxes = bboxes.shape[1] width = bboxes[2, ...] - bboxes[0, ...] height = bboxes[3, ...] - bboxes[1, ...] max_size = np.maximum(width, height) scalars = np.zeros((2, num_boxes)) scalars[0, ...] = max_size * 1.0 / width scalars[1, ...] = max_size * 1.0 / height return scale_bbox(bboxes, scalars, in_place=in_place)