-
Notifications
You must be signed in to change notification settings - Fork 7.1k
[prototype] Add support of inplace on convert_format_bounding_box
#6858
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4383337
66b9e98
897f3f0
498a033
6155b2e
e23322b
008413a
9ae104e
2eb37b1
8451df1
664f0b2
fceb336
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,16 +38,14 @@ def horizontal_flip_bounding_box( | |
|
||
# TODO: Investigate if it makes sense from a performance perspective to have an implementation for every | ||
# BoundingBoxFormat instead of converting back and forth | ||
bounding_box = ( | ||
bounding_box.clone() | ||
if format == features.BoundingBoxFormat.XYXY | ||
else convert_format_bounding_box(bounding_box, old_format=format, new_format=features.BoundingBoxFormat.XYXY) | ||
bounding_box = convert_format_bounding_box( | ||
bounding_box.clone(), old_format=format, new_format=features.BoundingBoxFormat.XYXY, inplace=True | ||
datumbox marked this conversation as resolved.
Show resolved
Hide resolved
|
||
).reshape(-1, 4) | ||
|
||
bounding_box[:, [0, 2]] = spatial_size[1] - bounding_box[:, [2, 0]] | ||
|
||
return convert_format_bounding_box( | ||
bounding_box, old_format=features.BoundingBoxFormat.XYXY, new_format=format | ||
bounding_box, old_format=features.BoundingBoxFormat.XYXY, new_format=format, inplace=True | ||
datumbox marked this conversation as resolved.
Show resolved
Hide resolved
|
||
).reshape(shape) | ||
|
||
|
||
|
@@ -79,16 +77,14 @@ def vertical_flip_bounding_box( | |
|
||
# TODO: Investigate if it makes sense from a performance perspective to have an implementation for every | ||
# BoundingBoxFormat instead of converting back and forth | ||
bounding_box = ( | ||
bounding_box.clone() | ||
if format == features.BoundingBoxFormat.XYXY | ||
else convert_format_bounding_box(bounding_box, old_format=format, new_format=features.BoundingBoxFormat.XYXY) | ||
bounding_box = convert_format_bounding_box( | ||
bounding_box.clone(), old_format=format, new_format=features.BoundingBoxFormat.XYXY, inplace=True | ||
).reshape(-1, 4) | ||
|
||
bounding_box[:, [1, 3]] = spatial_size[0] - bounding_box[:, [3, 1]] | ||
|
||
return convert_format_bounding_box( | ||
bounding_box, old_format=features.BoundingBoxFormat.XYXY, new_format=format | ||
bounding_box, old_format=features.BoundingBoxFormat.XYXY, new_format=format, inplace=True | ||
).reshape(shape) | ||
|
||
|
||
|
@@ -412,7 +408,7 @@ def affine_bounding_box( | |
# out_bboxes should be of shape [N boxes, 4] | ||
|
||
return convert_format_bounding_box( | ||
out_bboxes, old_format=features.BoundingBoxFormat.XYXY, new_format=format | ||
out_bboxes, old_format=features.BoundingBoxFormat.XYXY, new_format=format, inplace=True | ||
datumbox marked this conversation as resolved.
Show resolved
Hide resolved
|
||
).reshape(original_shape) | ||
|
||
|
||
|
@@ -594,9 +590,9 @@ def rotate_bounding_box( | |
) | ||
|
||
return ( | ||
convert_format_bounding_box(out_bboxes, old_format=features.BoundingBoxFormat.XYXY, new_format=format).reshape( | ||
original_shape | ||
), | ||
convert_format_bounding_box( | ||
out_bboxes, old_format=features.BoundingBoxFormat.XYXY, new_format=format, inplace=True | ||
).reshape(original_shape), | ||
spatial_size, | ||
) | ||
|
||
|
@@ -815,18 +811,18 @@ def crop_bounding_box( | |
) -> Tuple[torch.Tensor, Tuple[int, int]]: | ||
# TODO: Investigate if it makes sense from a performance perspective to have an implementation for every | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes we don't have every conversion. I remember when adding I had discussion with Francisco that all conversions can simply go through intermediate xyxy conversion for sake of less complications. |
||
# BoundingBoxFormat instead of converting back and forth | ||
bounding_box = ( | ||
bounding_box.clone() | ||
if format == features.BoundingBoxFormat.XYXY | ||
else convert_format_bounding_box(bounding_box, old_format=format, new_format=features.BoundingBoxFormat.XYXY) | ||
bounding_box = convert_format_bounding_box( | ||
bounding_box.clone(), old_format=format, new_format=features.BoundingBoxFormat.XYXY, inplace=True | ||
) | ||
|
||
# Crop or implicit pad if left and/or top have negative values: | ||
bounding_box[..., 0::2] -= left | ||
bounding_box[..., 1::2] -= top | ||
|
||
return ( | ||
convert_format_bounding_box(bounding_box, old_format=features.BoundingBoxFormat.XYXY, new_format=format), | ||
convert_format_bounding_box( | ||
bounding_box, old_format=features.BoundingBoxFormat.XYXY, new_format=format, inplace=True | ||
), | ||
(height, width), | ||
) | ||
|
||
|
@@ -964,7 +960,7 @@ def perspective_bounding_box( | |
# out_bboxes should be of shape [N boxes, 4] | ||
|
||
return convert_format_bounding_box( | ||
out_bboxes, old_format=features.BoundingBoxFormat.XYXY, new_format=format | ||
out_bboxes, old_format=features.BoundingBoxFormat.XYXY, new_format=format, inplace=True | ||
).reshape(original_shape) | ||
|
||
|
||
|
@@ -1085,7 +1081,7 @@ def elastic_bounding_box( | |
out_bboxes = torch.cat([out_bbox_mins, out_bbox_maxs], dim=1).to(bounding_box.dtype) | ||
|
||
return convert_format_bounding_box( | ||
out_bboxes, old_format=features.BoundingBoxFormat.XYXY, new_format=format | ||
out_bboxes, old_format=features.BoundingBoxFormat.XYXY, new_format=format, inplace=True | ||
).reshape(original_shape) | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -119,51 +119,60 @@ def get_num_frames(inpt: features.VideoTypeJIT) -> int: | |
raise TypeError(f"The video should be a Tensor. Got {type(inpt)}") | ||
|
||
|
||
def _xywh_to_xyxy(xywh: torch.Tensor) -> torch.Tensor: | ||
xyxy = xywh.clone() | ||
def _xywh_to_xyxy(xywh: torch.Tensor, inplace: bool) -> torch.Tensor: | ||
xyxy = xywh if inplace else xywh.clone() | ||
xyxy[..., 2:] += xyxy[..., :2] | ||
return xyxy | ||
|
||
|
||
def _xyxy_to_xywh(xyxy: torch.Tensor) -> torch.Tensor: | ||
xywh = xyxy.clone() | ||
def _xyxy_to_xywh(xyxy: torch.Tensor, inplace: bool) -> torch.Tensor: | ||
xywh = xyxy if inplace else xyxy.clone() | ||
xywh[..., 2:] -= xywh[..., :2] | ||
return xywh | ||
|
||
|
||
def _cxcywh_to_xyxy(cxcywh: torch.Tensor) -> torch.Tensor: | ||
cx, cy, w, h = torch.unbind(cxcywh, dim=-1) | ||
x1 = cx - 0.5 * w | ||
y1 = cy - 0.5 * h | ||
x2 = cx + 0.5 * w | ||
y2 = cy + 0.5 * h | ||
return torch.stack((x1, y1, x2, y2), dim=-1).to(cxcywh.dtype) | ||
def _cxcywh_to_xyxy(cxcywh: torch.Tensor, inplace: bool) -> torch.Tensor: | ||
datumbox marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if not inplace: | ||
cxcywh = cxcywh.clone() | ||
|
||
# Trick to do fast division by 2 and ceil, without casting. It produces the same result as | ||
# `torchvision.ops._box_convert._box_cxcywh_to_xyxy`. | ||
half_wh = cxcywh[..., 2:].div(-2, rounding_mode=None if cxcywh.is_floating_point() else "floor").abs_() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a trick to do division by 2 and ceil if we deal with integers. Unfortunately For the record the faster version is: half_wh = cxcywh[..., 2:].div(2, rounding_mode=None if cxcywh.is_floating_point() else "floor") |
||
# (cx - width / 2) = x1, same for y1 | ||
cxcywh[..., :2].sub_(half_wh) | ||
# (x1 + width) = x2, same for y2 | ||
cxcywh[..., 2:].add_(cxcywh[..., :2]) | ||
|
||
def _xyxy_to_cxcywh(xyxy: torch.Tensor) -> torch.Tensor: | ||
x1, y1, x2, y2 = torch.unbind(xyxy, dim=-1) | ||
cx = (x1 + x2) / 2 | ||
cy = (y1 + y2) / 2 | ||
w = x2 - x1 | ||
h = y2 - y1 | ||
return torch.stack((cx, cy, w, h), dim=-1).to(xyxy.dtype) | ||
return cxcywh | ||
|
||
|
||
def _xyxy_to_cxcywh(xyxy: torch.Tensor, inplace: bool) -> torch.Tensor: | ||
if not inplace: | ||
xyxy = xyxy.clone() | ||
|
||
# (x2 - x1) = width, same for height | ||
xyxy[..., 2:].sub_(xyxy[..., :2]) | ||
# (x1 * 2 + width) / 2 = x1 + width / 2 = x1 + (x2-x1)/2 = (x1 + x2)/2 = cx, same for cy | ||
xyxy[..., :2].mul_(2).add_(xyxy[..., 2:]).div_(2, rounding_mode=None if xyxy.is_floating_point() else "floor") | ||
|
||
return xyxy | ||
|
||
|
||
def convert_format_bounding_box( | ||
bounding_box: torch.Tensor, old_format: BoundingBoxFormat, new_format: BoundingBoxFormat | ||
bounding_box: torch.Tensor, old_format: BoundingBoxFormat, new_format: BoundingBoxFormat, inplace: bool = False | ||
) -> torch.Tensor: | ||
if new_format == old_format: | ||
return bounding_box | ||
|
||
if old_format == BoundingBoxFormat.XYWH: | ||
bounding_box = _xywh_to_xyxy(bounding_box) | ||
bounding_box = _xywh_to_xyxy(bounding_box, inplace) | ||
datumbox marked this conversation as resolved.
Show resolved
Hide resolved
|
||
elif old_format == BoundingBoxFormat.CXCYWH: | ||
bounding_box = _cxcywh_to_xyxy(bounding_box) | ||
bounding_box = _cxcywh_to_xyxy(bounding_box, inplace) | ||
|
||
if new_format == BoundingBoxFormat.XYWH: | ||
bounding_box = _xyxy_to_xywh(bounding_box) | ||
bounding_box = _xyxy_to_xywh(bounding_box, inplace) | ||
elif new_format == BoundingBoxFormat.CXCYWH: | ||
bounding_box = _xyxy_to_cxcywh(bounding_box) | ||
bounding_box = _xyxy_to_cxcywh(bounding_box, inplace) | ||
|
||
return bounding_box | ||
|
||
|
@@ -173,14 +182,12 @@ def clamp_bounding_box( | |
) -> torch.Tensor: | ||
# TODO: Investigate if it makes sense from a performance perspective to have an implementation for every | ||
# BoundingBoxFormat instead of converting back and forth | ||
xyxy_boxes = ( | ||
bounding_box.clone() | ||
if format == BoundingBoxFormat.XYXY | ||
else convert_format_bounding_box(bounding_box, format, BoundingBoxFormat.XYXY) | ||
xyxy_boxes = convert_format_bounding_box( | ||
bounding_box.clone(), old_format=format, new_format=features.BoundingBoxFormat.XYXY, inplace=True | ||
) | ||
xyxy_boxes[..., 0::2].clamp_(min=0, max=spatial_size[1]) | ||
xyxy_boxes[..., 1::2].clamp_(min=0, max=spatial_size[0]) | ||
return convert_format_bounding_box(xyxy_boxes, BoundingBoxFormat.XYXY, format) | ||
return convert_format_bounding_box(xyxy_boxes, old_format=BoundingBoxFormat.XYXY, new_format=format, inplace=True) | ||
|
||
|
||
def _strip_alpha(image: torch.Tensor) -> torch.Tensor: | ||
|
Uh oh!
There was an error while loading. Please reload this page.