| """ |
| This file has functions about bounding box processing. |
| """ |
| |
| import numpy as np |
| |
| |
| def bbox_transform(ex_rois, gt_rois): |
| """ |
| compute bounding box regression targets from ex_rois to gt_rois |
| :param ex_rois: [N, 4] |
| :param gt_rois: [N, 4] |
| :return: [N, 4] |
| """ |
| ex_widths = ex_rois[:, 2] - ex_rois[:, 0] + 1.0 |
| ex_heights = ex_rois[:, 3] - ex_rois[:, 1] + 1.0 |
| ex_ctr_x = ex_rois[:, 0] + 0.5 * (ex_widths - 1.0) |
| ex_ctr_y = ex_rois[:, 1] + 0.5 * (ex_heights - 1.0) |
| |
| gt_widths = gt_rois[:, 2] - gt_rois[:, 0] + 1.0 |
| gt_heights = gt_rois[:, 3] - gt_rois[:, 1] + 1.0 |
| gt_ctr_x = gt_rois[:, 0] + 0.5 * (gt_widths - 1.0) |
| gt_ctr_y = gt_rois[:, 1] + 0.5 * (gt_heights - 1.0) |
| |
| targets_dx = (gt_ctr_x - ex_ctr_x) / (ex_widths + 1e-14) |
| targets_dy = (gt_ctr_y - ex_ctr_y) / (ex_heights + 1e-14) |
| targets_dw = np.log(gt_widths / ex_widths) |
| targets_dh = np.log(gt_heights / ex_heights) |
| |
| targets = np.vstack( |
| (targets_dx, targets_dy, targets_dw, targets_dh)).transpose() |
| return targets |
| |
| |
| def bbox_pred(boxes, box_deltas, is_train=False): |
| """ |
| Transform the set of class-agnostic boxes into class-specific boxes |
| by applying the predicted offsets (box_deltas) |
| :param boxes: !important [N 4] |
| :param box_deltas: [N, 4 * num_classes] |
| :return: [N 4 * num_classes] |
| """ |
| if boxes.shape[0] == 0: |
| return np.zeros((0, box_deltas.shape[1])) |
| |
| boxes = boxes.astype(np.float, copy=False) |
| widths = boxes[:, 2] - boxes[:, 0] + 1.0 |
| heights = boxes[:, 3] - boxes[:, 1] + 1.0 |
| ctr_x = boxes[:, 0] + 0.5 * (widths - 1.0) |
| ctr_y = boxes[:, 1] + 0.5 * (heights - 1.0) |
| |
| dx = box_deltas[:, 0::4] |
| dy = box_deltas[:, 1::4] |
| dw = box_deltas[:, 2::4] |
| dh = box_deltas[:, 3::4] |
| if is_train: |
| dx = np.array(map(lambda x: np.sign(x)*10 if abs(x) > 10 else x, dx)) |
| dy = np.array(map(lambda x: np.sign(x)*10 if abs(x) > 10 else x, dy)) |
| pred_ctr_x = dx * widths[:, np.newaxis] + ctr_x[:, np.newaxis] |
| pred_ctr_y = dy * heights[:, np.newaxis] + ctr_y[:, np.newaxis] |
| |
| if is_train: |
| dw = np.array(map(lambda x: np.sign(x)*8 if abs(x) > 8 else x, dw)) |
| dh = np.array(map(lambda x: np.sign(x)*8 if abs(x) > 8 else x, dh)) |
| pred_w = np.exp(dw) * widths[:, np.newaxis] |
| pred_h = np.exp(dh) * heights[:, np.newaxis] |
| |
| pred_boxes = np.zeros(box_deltas.shape) |
| # x1 |
| pred_boxes[:, 0::4] = pred_ctr_x - 0.5 * (pred_w - 1.0) |
| # y1 |
| pred_boxes[:, 1::4] = pred_ctr_y - 0.5 * (pred_h - 1.0) |
| # x2 |
| pred_boxes[:, 2::4] = pred_ctr_x + 0.5 * (pred_w - 1.0) |
| # y2 |
| pred_boxes[:, 3::4] = pred_ctr_y + 0.5 * (pred_h - 1.0) |
| |
| return pred_boxes |
| |
| |
| def clip_boxes(boxes, im_shape): |
| """ |
| Clip boxes to image boundaries. |
| :param boxes: [N, 4* num_classes] |
| :param im_shape: tuple of 2 |
| :return: [N, 4* num_classes] |
| """ |
| # x1 >= 0 |
| boxes[:, 0::4] = np.maximum(np.minimum(boxes[:, 0::4], im_shape[1] - 1), 0) |
| # y1 >= 0 |
| boxes[:, 1::4] = np.maximum(np.minimum(boxes[:, 1::4], im_shape[0] - 1), 0) |
| # x2 < im_shape[1] |
| boxes[:, 2::4] = np.maximum(np.minimum(boxes[:, 2::4], im_shape[1] - 1), 0) |
| # y2 < im_shape[0] |
| boxes[:, 3::4] = np.maximum(np.minimum(boxes[:, 3::4], im_shape[0] - 1), 0) |
| return boxes |
| |
| def clip_pad(boxes, pad_shape): |
| """ |
| Clip boxes of the pad area. |
| :param boxes: [n, c, H, W] |
| :param im_shape: [h, w] |
| :return: [n, c, h, w] |
| """ |
| H, W = boxes.shape[2:] |
| h, w = pad_shape |
| if h < H: |
| boxes = boxes[:, :, :h, :].copy() |
| if w < W: |
| boxes = boxes[:, :, :, :w].copy() |
| return boxes |