Ejemplo n.º 1
0
    def test_iou_0_dim_cpu(self):
        boxes1 = torch.rand(0, 5, dtype=torch.float32)
        boxes2 = torch.rand(10, 5, dtype=torch.float32)
        expected_ious = torch.zeros(0, 10, dtype=torch.float32)
        ious = pairwise_iou_rotated(boxes1, boxes2)
        assert torch.allclose(ious, expected_ious)

        boxes1 = torch.rand(10, 5, dtype=torch.float32)
        boxes2 = torch.rand(0, 5, dtype=torch.float32)
        expected_ious = torch.zeros(10, 0, dtype=torch.float32)
        ious = pairwise_iou_rotated(boxes1, boxes2)
        assert torch.allclose(ious, expected_ious)
Ejemplo n.º 2
0
 def test_iou_issue_2167(self):
     for device in ["cpu"
                    ] + (["cuda"] if torch.cuda.is_available() else []):
         boxes1 = torch.tensor(
             [[
                 2563.74462890625000000000,
                 1436.79016113281250000000,
                 2174.70336914062500000000,
                 214.09500122070312500000,
                 115.11834716796875000000,
             ]],
             device=device,
         )
         boxes2 = torch.tensor(
             [[
                 2563.74462890625000000000,
                 1436.79028320312500000000,
                 2174.70288085937500000000,
                 214.09495544433593750000,
                 115.11835479736328125000,
             ]],
             device=device,
         )
         ious = pairwise_iou_rotated(boxes1, boxes2)
         expected_ious = torch.tensor([[1.0]], dtype=torch.float32)
         self.assertTrue(torch.allclose(ious.cpu(), expected_ious))
Ejemplo n.º 3
0
 def test_iou_half_overlap_cpu(self):
     boxes1 = torch.tensor([[0.5, 0.5, 1.0, 1.0, 0.0]], dtype=torch.float32)
     boxes2 = torch.tensor([[0.25, 0.5, 0.5, 1.0, 0.0]],
                           dtype=torch.float32)
     expected_ious = torch.tensor([[0.5]], dtype=torch.float32)
     ious = pairwise_iou_rotated(boxes1, boxes2)
     assert torch.allclose(ious, expected_ious)
Ejemplo n.º 4
0
 def test_iou_precision_cpu(self):
     boxes1 = torch.tensor([[565, 565, 10, 10, 0]], dtype=torch.float32)
     boxes2 = torch.tensor([[565, 565, 10, 8.3, 0]], dtype=torch.float32)
     iou = 8.3 / 10.0
     expected_ious = torch.tensor([[iou]], dtype=torch.float32)
     ious = pairwise_iou_rotated(boxes1, boxes2)
     assert torch.allclose(ious, expected_ious)
Ejemplo n.º 5
0
 def test_iou_perpendicular_cpu(self):
     boxes1 = torch.tensor([[5, 5, 10.0, 6, 55]], dtype=torch.float32)
     boxes2 = torch.tensor([[5, 5, 10.0, 6, -35]], dtype=torch.float32)
     iou = (6.0 * 6.0) / (6.0 * 6.0 + 4.0 * 6.0 + 4.0 * 6.0)
     expected_ious = torch.tensor([[iou]], dtype=torch.float32)
     ious = pairwise_iou_rotated(boxes1, boxes2)
     assert torch.allclose(ious, expected_ious)
Ejemplo n.º 6
0
 def test_iou_precision(self):
     for device in ["cpu"] + ["cuda"] if torch.cuda.is_available() else []:
         boxes1 = torch.tensor([[565, 565, 10, 10.0, 0]],
                               dtype=torch.float32,
                               device=device)
         boxes2 = torch.tensor([[565, 565, 10, 8.3, 0]],
                               dtype=torch.float32,
                               device=device)
         iou = 8.3 / 10.0
         expected_ious = torch.tensor([[iou]], dtype=torch.float32)
         ious = pairwise_iou_rotated(boxes1, boxes2)
         self.assertTrue(torch.allclose(ious.cpu(), expected_ious))
Ejemplo n.º 7
0
 def test_iou_extreme(self):
     # Cause floating point issues in cuda kernels (#1266)
     for device in ["cpu"] + ["cuda"] if torch.cuda.is_available() else []:
         boxes1 = torch.tensor([[160.0, 153.0, 230.0, 23.0, -37.0]],
                               device=device)
         boxes2 = torch.tensor(
             [[
                 -1.117407639806935e17,
                 1.3858420478349148e18,
                 1000.0000610351562,
                 1000.0000610351562,
                 1612.0,
             ]],
             device=device,
         )
         ious = pairwise_iou_rotated(boxes1, boxes2)
         self.assertTrue(ious.min() >= 0, ious)
Ejemplo n.º 8
0
 def test_iou_issue_2154(self):
     for device in ["cpu"
                    ] + (["cuda"] if torch.cuda.is_available() else []):
         boxes1 = torch.tensor(
             [[
                 296.6620178222656,
                 458.73883056640625,
                 23.515729904174805,
                 47.677001953125,
                 0.08795166015625,
             ]],
             device=device,
         )
         boxes2 = torch.tensor(
             [[296.66201, 458.73882000000003, 23.51573, 47.67702, 0.087951]
              ],
             device=device,
         )
         ious = pairwise_iou_rotated(boxes1, boxes2)
         expected_ious = torch.tensor([[1.0]], dtype=torch.float32)
         self.assertTrue(torch.allclose(ious.cpu(), expected_ious))
Ejemplo n.º 9
0
 def test_iou_0_degree_cpu(self):
     boxes1 = torch.tensor(
         [[0.5, 0.5, 1.0, 1.0, 0.0], [0.5, 0.5, 1.0, 1.0, 0.0]],
         dtype=torch.float32)
     boxes2 = torch.tensor(
         [
             [0.5, 0.5, 1.0, 1.0, 0.0],
             [0.25, 0.5, 0.5, 1.0, 0.0],
             [0.5, 0.25, 1.0, 0.5, 0.0],
             [0.25, 0.25, 0.5, 0.5, 0.0],
             [0.75, 0.75, 0.5, 0.5, 0.0],
             [1.0, 1.0, 1.0, 1.0, 0.0],
         ],
         dtype=torch.float32,
     )
     expected_ious = torch.tensor(
         [
             [1.0, 0.5, 0.5, 0.25, 0.25, 0.25 / (2 - 0.25)],
             [1.0, 0.5, 0.5, 0.25, 0.25, 0.25 / (2 - 0.25)],
         ],
         dtype=torch.float32,
     )
     ious = pairwise_iou_rotated(boxes1, boxes2)
     assert torch.allclose(ious, expected_ious)
Ejemplo n.º 10
0
def pairwise_iou(boxes1, boxes2):
    # (x_center, y_center, width, height, angle)
    boxes1, boxes2 = torch.from_numpy(boxes1).to(
        dtype=torch.float32), torch.from_numpy(boxes2).to(dtype=torch.float32)
    iou = pairwise_iou_rotated(boxes1, boxes2)
    return iou.numpy()
Ejemplo n.º 11
0
def voc_eval(detpath,
             annopath,
             imagesetfile,
             classname,
             ovthresh=0.5,
             use_07_metric=False,
             eval_type='hw'):
    """rec, prec, ap = voc_eval(detpath,
                                annopath,
                                imagesetfile,
                                classname,
                                [ovthresh],
                                [use_07_metric])

    Top level function that does the PASCAL VOC evaluation.

    detpath: Path to detections
        detpath.format(classname) should produce the detection results file.
    annopath: Path to annotations
        annopath.format(imagename) should be the xml annotations file.
    imagesetfile: Text file containing the list of images, one image per line.
    classname: Category name (duh)
    [ovthresh]: Overlap threshold (default = 0.5)
    [use_07_metric]: Whether to use VOC07's 11 point AP computation
        (default False)
    """
    # assumes detections are in detpath.format(classname)
    # assumes annotations are in annopath.format(imagename)
    # assumes imagesetfile is a text file with each line an image name

    # first load gt
    # read list of images
    with open(imagesetfile, "r") as f:
        lines = f.readlines()
    imagenames = [x.strip() for x in lines]

    # load annots
    recs = {}
    for imagename in imagenames:
        recs[imagename] = parse_rec(annopath.format(imagename))

    # extract gt objects for this class
    class_recs = {}
    npos = 0
    reshape_num = 4
    box_type = "obbox"
    if eval_type == 'hbb':
        box_type = "hrbb_box"
        reshape_num = 4
    if eval_type == 'hw':
        box_type = "obbox"
        reshape_num = 8
    else:
        box_type = "rotbox"
        reshape_num = 5

    for imagename in imagenames:
        R = [obj for obj in recs[imagename] if obj["name"] == classname]

        bbox = np.array([x[box_type] for x in R])
        difficult = np.array([x["difficult"] for x in R]).astype(np.bool)
        # difficult = np.array([False for x in R]).astype(np.bool)  # treat all "difficult" as GT
        det = [False] * len(R)
        npos = npos + sum(~difficult)
        class_recs[imagename] = {
            "bbox": bbox,
            "difficult": difficult,
            "det": det
        }

    # read dets
    detfile = detpath.format(classname)
    with open(detfile, "r") as f:
        lines = f.readlines()

    splitlines = [x.strip().split(" ") for x in lines]
    image_ids = [x[0] for x in splitlines]
    confidence = np.array([float(x[1]) for x in splitlines])

    BB = np.array([[float(z) for z in x[2:]]
                   for x in splitlines]).reshape(-1, reshape_num)

    # sort by confidence
    sorted_ind = np.argsort(-confidence)
    BB = BB[sorted_ind, :]
    image_ids = [image_ids[x] for x in sorted_ind]

    # go down dets and mark TPs and FPs
    nd = len(image_ids)
    tp = np.zeros(nd)
    fp = np.zeros(nd)

    for d in range(nd):
        R = class_recs[image_ids[d]]
        bb = BB[d, :].astype(float)
        ovmax = -np.inf
        BBGT = R["bbox"].astype(float)

        if BBGT.size > 0:
            # compute overlaps
            # intersection
            if eval_type == 'hbb':
                ixmin = np.maximum(BBGT[:, 0], bb[0])
                iymin = np.maximum(BBGT[:, 1], bb[1])
                ixmax = np.minimum(BBGT[:, 2], bb[2])
                iymax = np.minimum(BBGT[:, 3], bb[3])
                iw = np.maximum(ixmax - ixmin + 1.0, 0.0)
                ih = np.maximum(iymax - iymin + 1.0, 0.0)
                inters = iw * ih

                # union
                uni = ((bb[2] - bb[0] + 1.0) * (bb[3] - bb[1] + 1.0) +
                       (BBGT[:, 2] - BBGT[:, 0] + 1.0) *
                       (BBGT[:, 3] - BBGT[:, 1] + 1.0) - inters)

                overlaps = inters / uni
                ovmax = np.max(overlaps)
                jmax = np.argmax(overlaps)
            if eval_type == 'hw':
                # else:
                # compute overlaps
                # intersection

                # 1. calculate the overlaps between hbbs, if the iou between hbbs are 0, the iou between obbs are 0, too.
                # pdb.set_trace()
                BBGT_xmin = np.min(BBGT[:, 0::2], axis=1)
                BBGT_ymin = np.min(BBGT[:, 1::2], axis=1)
                BBGT_xmax = np.max(BBGT[:, 0::2], axis=1)
                BBGT_ymax = np.max(BBGT[:, 1::2], axis=1)
                bb_xmin = np.min(bb[0::2])
                bb_ymin = np.min(bb[1::2])
                bb_xmax = np.max(bb[0::2])
                bb_ymax = np.max(bb[1::2])

                ixmin = np.maximum(BBGT_xmin, bb_xmin)
                iymin = np.maximum(BBGT_ymin, bb_ymin)
                ixmax = np.minimum(BBGT_xmax, bb_xmax)
                iymax = np.minimum(BBGT_ymax, bb_ymax)
                iw = np.maximum(ixmax - ixmin + 1., 0.)
                ih = np.maximum(iymax - iymin + 1., 0.)
                inters = iw * ih

                # union
                uni = ((bb_xmax - bb_xmin + 1.) * (bb_ymax - bb_ymin + 1.) +
                       (BBGT_xmax - BBGT_xmin + 1.) *
                       (BBGT_ymax - BBGT_ymin + 1.) - inters)

                overlaps = inters / uni

                BBGT_keep_mask = overlaps > 0
                BBGT_keep = BBGT[BBGT_keep_mask, :]
                BBGT_keep_index = np.where(overlaps > 0)[0]

                # pdb.set_trace()
                def calcoverlaps(BBGT_keep, bb):
                    overlaps = []
                    for index, GT in enumerate(BBGT_keep):

                        overlap = polyiou.iou_poly(
                            polyiou.VectorDouble(BBGT_keep[index]),
                            polyiou.VectorDouble(bb))
                        overlaps.append(overlap)
                    return overlaps

                if len(BBGT_keep) > 0:
                    overlaps = calcoverlaps(BBGT_keep, bb)

                    ovmax = np.max(overlaps)
                    jmax = np.argmax(overlaps)
                    # pdb.set_trace()
                    jmax = BBGT_keep_index[jmax]
            else:
                BBGT_gpu = torch.from_numpy(BBGT).view(-1, 5).float().cuda()
                bb_gpu = torch.from_numpy(bb).view(-1, 5).float().cuda()
                overlaps = pairwise_iou_rotated(BBGT_gpu, bb_gpu).cpu()
                overlaps = overlaps.view(-1).numpy()
                ovmax = np.max(overlaps)
                jmax = np.argmax(overlaps)

        if ovmax > ovthresh:
            if not R["difficult"][jmax]:
                if not R["det"][jmax]:
                    tp[d] = 1.0
                    R["det"][jmax] = 1
                else:
                    fp[d] = 1.0
        else:
            fp[d] = 1.0

    # compute precision recall
    fp = np.cumsum(fp)
    tp = np.cumsum(tp)
    rec = tp / float(npos)
    # avoid divide by zero in case the first detection matches a difficult
    # ground truth
    prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)
    ap = voc_ap(rec, prec, use_07_metric)

    return rec, prec, ap
Ejemplo n.º 12
0
    def cal_target(self, gt_box3d, gt_xyzhwlr, cfg):
        # Input:
        #   labels: (N,)
        #   feature_map_shape: (w, l)
        #   anchors: (w, l, 2, 7)
        # Output:
        #   pos_equal_one (w, l, 2)
        #   neg_equal_one (w, l, 2)
        #   targets (w, l, 14)
        # attention: cal IoU on birdview

        anchors_d = torch.sqrt(self.anchors[:, 4]**2 +
                               self.anchors[:, 5]**2).to(cfg.device)
        # denote whether the anchor box is pos or neg
        pos_equal_one = torch.zeros(
            (*self.feature_map_shape, 2)).to(cfg.device)
        neg_equal_one = torch.zeros(
            (*self.feature_map_shape, 2)).to(cfg.device)

        targets = torch.zeros((*self.feature_map_shape, 14)).to(cfg.device)

        gt_xyzhwlr = torch.tensor(gt_xyzhwlr,
                                  requires_grad=False).float().to(cfg.device)
        gt_xylwr = gt_xyzhwlr[..., [0, 1, 5, 4, 6]]

        # BOTTLENECK

        iou = pairwise_iou_rotated(
            self.anchors_xylwr,
            gt_xylwr.contiguous()).cpu().numpy()  # (gt - anchor)

        id_highest = np.argmax(iou.T, axis=1)  # the maximum anchor's ID
        id_highest_gt = np.arange(iou.T.shape[0])
        mask = iou.T[id_highest_gt,
                     id_highest] > 0  # make sure all the iou is positive
        id_highest, id_highest_gt = id_highest[mask], id_highest_gt[mask]

        # find anchor iou > cfg.XXX_POS_IOU
        id_pos, id_pos_gt = np.where(iou > self.pos_threshold)
        # find anchor iou < cfg.XXX_NEG_IOU
        id_neg = np.where(
            np.sum(iou < self.neg_threshold, axis=1) == iou.shape[1])[
                0]  # anchor doesn't match ant ground truth

        for gt in range(iou.shape[1]):
            if gt not in id_pos_gt and iou[id_highest[gt],
                                           gt] > self.neg_threshold:
                id_pos = np.append(id_pos, id_highest[gt])
                id_pos_gt = np.append(id_pos_gt, gt)

        # sample the negative points to keep ratio as 1:10 with minimum 500
        num_neg = 10 * id_pos.shape[0]
        if num_neg < 500:
            num_neg = 500
        if id_neg.shape[0] > num_neg:
            np.random.shuffle(id_neg)
            id_neg = id_neg[:num_neg]
        # cal the target and set the equal one
        index_x, index_y, index_z = np.unravel_index(
            id_pos, (*self.feature_map_shape, self.anchors_per_position))
        pos_equal_one[index_x, index_y, index_z] = 1
        # ATTENTION: index_z should be np.array

        # parameterize the ground truth box relative to anchor boxs
        targets[index_x, index_y, np.array(index_z) * 7] = \
            (gt_xyzhwlr[id_pos_gt, 0] - self.anchors[id_pos, 0]) / anchors_d[id_pos]
        targets[index_x, index_y, np.array(index_z) * 7 + 1] = \
            (gt_xyzhwlr[id_pos_gt, 1] - self.anchors[id_pos, 1]) / anchors_d[id_pos]
        targets[index_x, index_y, np.array(index_z) * 7 + 2] = \
            (gt_xyzhwlr[id_pos_gt, 2] - self.anchors[id_pos, 2]) / self.anchors[id_pos, 3]
        targets[index_x, index_y, np.array(index_z) * 7 + 3] = torch.log(
            gt_xyzhwlr[id_pos_gt, 3] / self.anchors[id_pos, 3])
        targets[index_x, index_y, np.array(index_z) * 7 + 4] = torch.log(
            gt_xyzhwlr[id_pos_gt, 4] / self.anchors[id_pos, 4])
        targets[index_x, index_y, np.array(index_z) * 7 + 5] = torch.log(
            gt_xyzhwlr[id_pos_gt, 5] / self.anchors[id_pos, 5])
        targets[index_x, index_y, np.array(index_z) * 7 +
                6] = (gt_xyzhwlr[id_pos_gt, 6] - self.anchors[id_pos, 6])
        index_x, index_y, index_z = np.unravel_index(
            id_neg, (*self.feature_map_shape, self.anchors_per_position))
        neg_equal_one[index_x, index_y, index_z] = 1

        return pos_equal_one, neg_equal_one, targets