import torch from torchvision.ops.boxes import box_area import numpy as np def box_cxcywh_to_xyxy(x): x_c, y_c, w, h = x.unbind(-1) b = [(x_c - 0.5 * w), (y_c - 0.5 * h), (x_c + 0.5 * w), (y_c + 0.5 * h)] return torch.stack(b, dim=-1) def box_xywh_to_xyxy(x): x1, y1, w, h = x.unbind(-1) b = [x1, y1, x1 + w, y1 + h] return torch.stack(b, dim=-1) def box_xyxy_to_xywh(x): x1, y1, x2, y2 = x.unbind(-1) b = [x1, y1, x2 - x1, y2 - y1] return torch.stack(b, dim=-1) def box_xyxy_to_cxcywh(x): x0, y0, x1, y1 = x.unbind(-1) b = [(x0 + x1) / 2, (y0 + y1) / 2, (x1 - x0), (y1 - y0)] return torch.stack(b, dim=-1) # modified from torchvision to also return the union '''Note that this function only supports shape (N,4)''' def box_iou(boxes1, boxes2): """ :param boxes1: (N, 4) (x1,y1,x2,y2) :param boxes2: (N, 4) (x1,y1,x2,y2) :return: """ area1 = box_area(boxes1) # (N,) area2 = box_area(boxes2) # (N,) lt = torch.max(boxes1[:, :2], boxes2[:, :2]) # (N,2) rb = torch.min(boxes1[:, 2:], boxes2[:, 2:]) # (N,2) wh = (rb - lt).clamp(min=0) # (N,2) inter = wh[:, 0] * wh[:, 1] # (N,) union = area1 + area2 - inter iou = inter / union return iou, union '''Note that this implementation is different from DETR's''' def generalized_box_iou(boxes1, boxes2): """ Generalized IoU from https://giou.stanford.edu/ The boxes should be in [x0, y0, x1, y1] format boxes1: (N, 4) boxes2: (N, 4) """ # degenerate boxes gives inf / nan results # so do an early check # try: #assert (boxes1[:, 2:] >= boxes1[:, :2]).all() # assert (boxes2[:, 2:] >= boxes2[:, :2]).all() iou, union = box_iou(boxes1, boxes2) # (N,) lt = torch.min(boxes1[:, :2], boxes2[:, :2]) rb = torch.max(boxes1[:, 2:], boxes2[:, 2:]) wh = (rb - lt).clamp(min=0) # (N,2) area = wh[:, 0] * wh[:, 1] # (N,) return iou - (area - union) / area, iou def giou_loss(boxes1, boxes2): """ :param boxes1: (N, 4) (x1,y1,x2,y2) :param boxes2: (N, 4) (x1,y1,x2,y2) :return: """ giou, iou = generalized_box_iou(boxes1, boxes2) return (1 - giou).mean(), iou def clip_box(box: list, H, W, margin=0): x1, y1, w, h = box x2, y2 = x1 + w, y1 + h x1 = min(max(0, x1), W-margin) x2 = min(max(margin, x2), W) y1 = min(max(0, y1), H-margin) y2 = min(max(margin, y2), H) w = max(margin, x2-x1) h = max(margin, y2-y1) return [x1, y1, w, h]