Spaces:
Runtime error
Runtime error
#!/usr/bin/env python3 | |
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | |
import torch | |
from maskrcnn_benchmark.layers import nms as _box_nms | |
from .bounding_box import BoxList | |
from maskrcnn_benchmark.structures.segmentation_mask import SegmentationMask | |
import numpy as np | |
import shapely | |
from shapely.geometry import Polygon,MultiPoint | |
def boxlist_nms(boxlist, nms_thresh, max_proposals=-1, score_field="score"): | |
""" | |
Performs non-maximum suppression on a boxlist, with scores specified | |
in a boxlist field via score_field. | |
Arguments: | |
boxlist(BoxList) | |
nms_thresh (float) | |
max_proposals (int): if > 0, then only the top max_proposals are kept | |
after non-maxium suppression | |
score_field (str) | |
""" | |
if nms_thresh <= 0: | |
return boxlist | |
mode = boxlist.mode | |
boxlist = boxlist.convert("xyxy") | |
boxes = boxlist.bbox | |
score = boxlist.get_field(score_field) | |
keep = _box_nms(boxes, score, nms_thresh) | |
if max_proposals > 0: | |
keep = keep[:max_proposals] | |
boxlist = boxlist[keep] | |
return boxlist.convert(mode) | |
def remove_small_boxes(boxlist, min_size): | |
""" | |
Only keep boxes with both sides >= min_size | |
Arguments: | |
boxlist (Boxlist) | |
min_size (int) | |
""" | |
# TODO maybe add an API for querying the ws / hs | |
xywh_boxes = boxlist.convert("xywh").bbox | |
_, _, ws, hs = xywh_boxes.unbind(dim=1) | |
keep = ((ws >= min_size) & (hs >= min_size)).nonzero().squeeze(1) | |
return boxlist[keep] | |
# implementation from https://github.com/kuangliu/torchcv/blob/master/torchcv/utils/box.py | |
# with slight modifications | |
def boxlist_iou(boxlist1, boxlist2): | |
"""Compute the intersection over union of two set of boxes. | |
The box order must be (xmin, ymin, xmax, ymax). | |
Arguments: | |
box1: (BoxList) bounding boxes, sized [N,4]. | |
box2: (BoxList) bounding boxes, sized [M,4]. | |
Returns: | |
(tensor) iou, sized [N,M]. | |
Reference: | |
https://github.com/chainer/chainercv/blob/master/chainercv/utils/bbox/bbox_iou.py | |
""" | |
if boxlist1.size != boxlist2.size: | |
raise RuntimeError( | |
"boxlists should have same image size, got {}, {}".format( | |
boxlist1, boxlist2 | |
) | |
) | |
# N = len(boxlist1) | |
# M = len(boxlist2) | |
area1 = boxlist1.area() | |
area2 = boxlist2.area() | |
box1, box2 = boxlist1.bbox, boxlist2.bbox | |
lt = torch.max(box1[:, None, :2], box2[:, :2]) # [N,M,2] | |
rb = torch.min(box1[:, None, 2:], box2[:, 2:]) # [N,M,2] | |
TO_REMOVE = 1 | |
wh = (rb - lt + TO_REMOVE).clamp(min=0) # [N,M,2] | |
inter = wh[:, :, 0] * wh[:, :, 1] # [N,M] | |
iou = inter / (area1[:, None] + area2 - inter) | |
return iou | |
# def boxlist_polygon_iou(target, proposal): | |
# """Compute the intersection over union of two set of boxes. | |
# The box order must be (xmin, ymin, xmax, ymax). | |
# Arguments: | |
# box1: (BoxList) bounding boxes, sized [N,4]. | |
# box2: (BoxList) bounding boxes, sized [M,4]. | |
# Returns: | |
# (tensor) iou, sized [N,M]. | |
# Reference: | |
# https://github.com/chainer/chainercv/blob/master/chainercv/utils/bbox/bbox_iou.py | |
# """ | |
# if target.size != proposal.size: | |
# raise RuntimeError( | |
# "boxlists should have same image size, got {}, {}".format( | |
# target, proposal | |
# ) | |
# ) | |
# target_polygon = target.get_field("masks").to_np_polygon() | |
# proposal_polygon = proposal.get_field("masks").to_np_polygon() | |
# print(target_polygon) | |
# print(proposal_polygon) | |
# polygon_points1 = target_polygon[0].reshape(-1, 2) | |
# poly1 = Polygon(polygon_points1).convex_hull | |
# polygon_points2 = proposal_polygon[0].reshape(-1, 2) | |
# poly2 = Polygon(polygon_points2).convex_hull | |
# union_poly = np.concatenate((polygon_points1, polygon_points2)) | |
# if not poly1.intersects(poly2): # this test is fast and can accelerate calculation | |
# iou = 0 | |
# else: | |
# try: | |
# inter_area = poly1.intersection(poly2).area | |
# #union_area = poly1.area + poly2.area - inter_area | |
# union_area = MultiPoint(union_poly).convex_hull.area | |
# if union_area == 0: | |
# return 0 | |
# iou = float(inter_area) / union_area | |
# except shapely.geos.TopologicalError: | |
# print('shapely.geos.TopologicalError occured, iou set to 0') | |
# iou = 0 | |
# return iou | |
# TODO redundant, remove | |
def _cat(tensors, dim=0): | |
""" | |
Efficient version of torch.cat | |
avoids a copy if there is only a single element in a list | |
""" | |
assert isinstance(tensors, (list, tuple)) | |
if len(tensors) == 1: | |
return tensors[0] | |
return torch.cat(tensors, dim) | |
def _cat_mask(masks): | |
polygons_cat = [] | |
size = masks[0].size | |
for mask in masks: | |
polygons = mask.get_polygons() | |
polygons_cat.extend(polygons) | |
masks_cat = SegmentationMask(polygons_cat, size) | |
return masks_cat | |
def cat_boxlist(bboxes): | |
""" | |
Concatenates a list of BoxList (having the same image size) into a | |
single BoxList | |
Arguments: | |
bboxes (list[BoxList]) | |
""" | |
# if bboxes is None: | |
# return None | |
# if bboxes[0] is None: | |
# bboxes = [bboxes[1] | |
assert isinstance(bboxes, (list, tuple)) | |
assert all(isinstance(bbox, BoxList) for bbox in bboxes) | |
size = bboxes[0].size | |
assert all(bbox.size == size for bbox in bboxes) | |
mode = bboxes[0].mode | |
assert all(bbox.mode == mode for bbox in bboxes) | |
fields = set(bboxes[0].fields()) | |
assert all(set(bbox.fields()) == fields for bbox in bboxes) | |
cat_boxes = BoxList(_cat([bbox.bbox for bbox in bboxes], dim=0), size, mode) | |
for field in fields: | |
if field == 'masks': | |
data = _cat_mask([bbox.get_field(field) for bbox in bboxes]) | |
else: | |
data = _cat([bbox.get_field(field) for bbox in bboxes], dim=0) | |
cat_boxes.add_field(field, data) | |
return cat_boxes | |
def cat_boxlist_gt(bboxes): | |
""" | |
Concatenates a list of BoxList (having the same image size) into a | |
single BoxList | |
Arguments: | |
bboxes (list[BoxList]) | |
""" | |
assert isinstance(bboxes, (list, tuple)) | |
assert all(isinstance(bbox, BoxList) for bbox in bboxes) | |
size = bboxes[0].size | |
# bboxes[1].set_size(size) | |
assert all(bbox.size == size for bbox in bboxes) | |
mode = bboxes[0].mode | |
assert all(bbox.mode == mode for bbox in bboxes) | |
fields = set(bboxes[0].fields()) | |
assert all(set(bbox.fields()) == fields for bbox in bboxes) | |
if bboxes[0].bbox.sum().item() == 0: | |
cat_boxes = BoxList(bboxes[1].bbox, size, mode) | |
else: | |
cat_boxes = BoxList(_cat([bbox.bbox for bbox in bboxes], dim=0), size, mode) | |
for field in fields: | |
if bboxes[0].bbox.sum().item() == 0: | |
if field == 'masks': | |
data = _cat_mask([bbox.get_field(field) for bbox in bboxes[1:]]) | |
else: | |
data = _cat([bbox.get_field(field) for bbox in bboxes[1:]], dim=0) | |
else: | |
if field == 'masks': | |
data = _cat_mask([bbox.get_field(field) for bbox in bboxes]) | |
else: | |
data = _cat([bbox.get_field(field) for bbox in bboxes], dim=0) | |
cat_boxes.add_field(field, data) | |
return cat_boxes | |