Exemplo n.º 1
0
def boxes_to_node_features(boxes: Boxes, image_size: Tuple[int, int]):
    """Compute node features from the bounding boxes of detected objects.

    - Elongation (height / width)
    - Elongation (width / height)
    - Area relative to the total image area

    Args:
        boxes:
        image_size: (height, width)

    Returns:

    """
    height, width = image_size

    # Boxes are represented as N x (x1, y1, x2, y2):
    x_min, y_min, x_max, y_max = boxes.tensor.unbind(dim=1)
    elongation = (y_max - y_min) / (x_max - x_min)

    relative_area = boxes.area() / (height * width)

    nodes = torch.stack([elongation, 1 / elongation, relative_area], dim=1)

    return nodes
Exemplo n.º 2
0
    def _match_anchors(self, gt_boxes: Boxes, anchors: List[Boxes]):
        """
        Match ground-truth boxes to a set of multi-level anchors.

        Args:
            gt_boxes: Ground-truth boxes from instances of an image.
            anchors: List of anchors for each feature map (of different scales).

        Returns:
            torch.Tensor
                A tensor of shape `(M, R)`, given `M` ground-truth boxes and total
                `R` anchor points from all feature levels, indicating the quality
                of match between m-th box and r-th anchor. Higher value indicates
                better match.
        """
        # Naming convention: (M = ground-truth boxes, R = anchor points)
        # Anchor points are represented as square boxes of size = stride.
        num_anchors_per_level = [len(x) for x in anchors]
        anchors = Boxes.cat(anchors)  # (R, 4)
        anchor_centers = anchors.get_centers()  # (R, 2)
        anchor_sizes = anchors.tensor[:, 2] - anchors.tensor[:, 0]  # (R, )

        lower_bound = anchor_sizes * 4
        lower_bound[:num_anchors_per_level[0]] = 0
        upper_bound = anchor_sizes * 8
        upper_bound[-num_anchors_per_level[-1]:] = float("inf")

        gt_centers = gt_boxes.get_centers()

        # FCOS with center sampling: anchor point must be close enough to
        # ground-truth box center.
        center_dists = (anchor_centers[None, :, :] -
                        gt_centers[:, None, :]).abs_()
        sampling_regions = self.center_sampling_radius * anchor_sizes[None, :]

        match_quality_matrix = center_dists.max(
            dim=2).values < sampling_regions

        pairwise_dist = pairwise_point_box_distance(anchor_centers, gt_boxes)
        pairwise_dist = pairwise_dist.permute(1, 0, 2)  # (M, R, 4)

        # The original FCOS anchor matching rule: anchor point must be inside GT.
        match_quality_matrix &= pairwise_dist.min(dim=2).values > 0

        # Multilevel anchor matching in FCOS: each anchor is only responsible
        # for certain scale range.
        pairwise_dist = pairwise_dist.max(dim=2).values
        match_quality_matrix &= (pairwise_dist > lower_bound[None, :]) & (
            pairwise_dist < upper_bound[None, :])
        # Match the GT box with minimum area, if there are multiple GT matches.
        gt_areas = gt_boxes.area()  # (M, )

        match_quality_matrix = match_quality_matrix.to(torch.float32)
        match_quality_matrix *= 1e8 - gt_areas[:, None]
        return match_quality_matrix  # (M, R)
def get_selfarea_and_interarea(boxes1: Boxes, boxes2: Boxes) -> torch.Tensor:
    """
    Given two lists of boxes of size N and M,
    compute the IoU (intersection over union)
    between __all__ N x M pairs of boxes.
    The box order must be (xmin, ymin, xmax, ymax).

    Args:
        boxes1,boxes2 (Boxes): two `Boxes`. Contains N & N boxes, respectively.
    Returns:
        self_area: proposal_boxes_area, sized [N]
        inter_area: inter_area, sized [N,N].
    """
    self_area = boxes1.area()
    boxes1, boxes2 = boxes1.tensor, boxes2.tensor

    lt = torch.max(boxes1[:, None, :2], boxes2[:, :2])  
    rb = torch.min(boxes1[:, None, 2:], boxes2[:, 2:])  

    wh = (rb - lt).clamp(min=0)  
    inter_area = wh[:, :, 0] * wh[:, :, 1]  

    return self_area, inter_area
Exemplo n.º 4
0
 def func(x):
     boxes = Boxes(x)
     # https://github.com/pytorch/pytorch/pull/47734
     # test = boxes.to(torch.device("cpu")).tensor
     test = x
     return boxes.area(), test
Exemplo n.º 5
0
 def func(x):
     boxes = Boxes(x)
     test = boxes.to(torch.device("cpu")).tensor
     return boxes.area(), test
Exemplo n.º 6
0
 def func(x):
     boxes = Boxes(x)
     return boxes.area()
Exemplo n.º 7
0
def boxes_to_edge_features(boxes: Boxes, image_size: Tuple[int, int]):
    """Compute pairwise edge features from the bounding boxes of detected objects.

    - Euclidean distance between box centers relative to sqrt(area) of the image
    - Sin and cos of the delta between box centers
    - Intersection over union
    - Relative area of the first box w.r.t. the second box

    Args:
        boxes:
        image_size: (height, width)

    Returns:

    """
    height, width = image_size

    # Boxes are represented as N x (x1, y1, x2, y2):
    N = len(boxes)
    indices = torch.from_numpy(np.indices((N, N)).reshape(2, -1))  # 2 x (N*N)

    centers = boxes.get_centers()  # N x 2
    areas = boxes.area()  # N

    # delta[i, j] = centers[j] - centers[i]
    delta = centers[None, :, :] - centers[:, None, :]  # N x N x 2
    delta = delta.view(N * N, 2)  # N*N x 2
    relative_dist = delta.norm(dim=1) / np.sqrt(height * width)  # N*N
    angles = torch.atan2(delta[:, 1], delta[:, 0])  # N*N
    sin = torch.sin(angles)  # N*N
    cos = torch.cos(angles)  # N*N

    def quantize_angles(angles):
        """Quantize angles in the ranges 45-135, 135-225, 225-315, 315-45"""
        angles = angles - np.pi / 4
        top_half = torch.sin(angles) >= 0
        right_half = torch.sin(angles) >= 0

        result = torch.empty(len(angles), 4, dtype=torch.bool)
        result[:, 0] = top_half & right_half
        result[:, 1] = top_half & ~right_half
        result[:, 2] = ~top_half & ~right_half
        result[:, 3] = ~top_half & right_half

        return result.float()

    quadrants = quantize_angles(angles)

    iou = pairwise_iou(boxes, boxes)  # N x N
    iou = iou.view(N * N)  # N*N

    # relative_area[i, j] = area[i] / area[j]
    relative_area = areas[:, None] / areas[None, :]  # N x N
    relative_area = relative_area.view(N * N)  # N*N

    features = torch.stack(
        [
            relative_dist,
            sin,
            cos,
            *quadrants.unbind(dim=1),
            iou,
            relative_area,
            1 / relative_area,
        ],
        dim=1,
    )  # N x num_feats

    # Remove elements on the diagonal (i.e. self-relationships)
    mask = indices[0] != indices[1]
    features = features[mask]  # (N*N - N) x 4
    indices = indices[:, mask]  # 2 x (N*N -1)

    return features, indices