import torch


def bbox_transform(boxes, gtboxes):
    """ Bounding Box Transform
    from groundtruth boxes and proposal boxes to deltas

    Args:
        boxes: [N, 4] torch.Tensor (xyxy)
        gtboxes: [N, 4] torch.Tensor  (xywh)
    Return:
        delta: [N, 4] torch.Tensor
    """
    gt_w = gtboxes[:, 2] - gtboxes[:, 0] + 1
    gt_h = gtboxes[:, 3] - gtboxes[:, 1] + 1
    # center
    gt_x = gtboxes[:, 0] + 0.5 * gt_w
    gt_y = gtboxes[:, 1] + 0.5 * gt_h

    # Anchors [x,y,w,h]
    anchor_x = boxes[:, 0]
    anchor_y = boxes[:, 1]
    anchor_w = boxes[:, 2]
    anchor_h = boxes[:, 3]

    delta_x = (gt_x - anchor_x) / anchor_w
    delta_y = (gt_y - anchor_y) / anchor_h
    delta_w = torch.log(gt_w / anchor_w)
    delta_h = torch.log(gt_h / anchor_h)

    # [N, 4]
    return torch.stack([delta_x, delta_y, delta_w, delta_h]).transpose(0, 1)