in seamseg/algos/detection.py [0:0]
def __call__(self,
proposals,
bbx,
cat,
iscrowd):
"""Match proposals to ground truth boxes
Parameters
----------
proposals : PackedSequence
A sequence of N tensors with shapes P_i x 4 containing bounding box proposals, entries can be None
bbx : sequence of torch.Tensor
A sequence of N tensors with shapes K_i x 4 containing ground truth bounding boxes, entries can be None
cat : sequence of torch.Tensor
A sequence of N tensors with shapes K_i containing ground truth instance -> category mappings, entries can
be None
iscrowd : sequence of torch.Tensor
Sequence of N tensors of ground truth crowd regions (shapes H_i x W_i), or ground truth crowd bounding boxes
(shapes K_i x 4), entries can be None
Returns
-------
out_proposals : PackedSequence
A sequence of N tensors with shapes S_i x 4 containing the non-void bounding box proposals, entries are None
for images that do not contain any non-void proposal
match : PackedSequence
A sequence of matching results with shape S_i, with the following semantic:
- match[i, j] == -1: the j-th anchor in image i is negative
- match[i, j] == k, k >= 0: the j-th anchor in image i is matched to bbx[i][k]
"""
out_proposals = []
match = []
for proposals_i, bbx_i, cat_i, iscrowd_i in zip(proposals, bbx, cat, iscrowd):
try:
# Append proposals to ground truth bounding boxes before proceeding
if bbx_i is not None and proposals_i is not None:
proposals_i = torch.cat([bbx_i, proposals_i], dim=0)
elif bbx_i is not None:
proposals_i = bbx_i
else:
raise Empty
# Optionally check overlap with void
if self.void_threshold != 0 and iscrowd_i is not None:
if iscrowd_i.dtype == torch.uint8:
overlap = mask_overlap(proposals_i, iscrowd_i)
else:
overlap = bbx_overlap(proposals_i, iscrowd_i)
overlap, _ = overlap.max(dim=1)
valid = overlap < self.void_threshold
proposals_i = proposals_i[valid]
if proposals_i.size(0) == 0:
raise Empty
# Find positives and negatives based on IoU
if bbx_i is not None:
iou = ious(proposals_i, bbx_i)
best_iou, best_gt = iou.max(dim=1)
pos_idx = best_iou >= self.pos_threshold
neg_idx = (best_iou >= self.neg_threshold_lo) & (best_iou < self.neg_threshold_hi)
else:
# No ground truth boxes: all proposals that are non-void are negative
pos_idx = proposals_i.new_zeros(proposals_i.size(0), dtype=torch.uint8)
neg_idx = proposals_i.new_ones(proposals_i.size(0), dtype=torch.uint8)
# Check that there are still some non-voids and do sub-sampling
if not pos_idx.any().item() and not neg_idx.any().item():
raise Empty
pos_idx, neg_idx = self._subsample(pos_idx, neg_idx)
# Gather selected proposals
out_proposals_i = proposals_i[torch.cat([pos_idx, neg_idx])]
# Save matching
match_i = out_proposals_i.new_full((out_proposals_i.size(0),), -1, dtype=torch.long)
match_i[:pos_idx.numel()] = best_gt[pos_idx]
# Save to output
out_proposals.append(out_proposals_i)
match.append(match_i)
except Empty:
out_proposals.append(None)
match.append(None)
return PackedSequence(out_proposals), PackedSequence(match)