Skip to content

Commit ffe2d2c

Browse files
committed
Merge branch 'main' of github.com:pytorch/vision into bb_tutorial
2 parents 4b5aa91 + d247de8 commit ffe2d2c

File tree

9 files changed

+56
-25
lines changed

9 files changed

+56
-25
lines changed
3.05 KB
Loading

test/test_transforms_v2.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5526,7 +5526,7 @@ def test_correctness_image(self, mean, std, dtype, fn):
55265526

55275527
class TestClampBoundingBoxes:
55285528
@pytest.mark.parametrize("format", list(tv_tensors.BoundingBoxFormat))
5529-
@pytest.mark.parametrize("clamping_mode", ("hard", None)) # TODOBB add soft
5529+
@pytest.mark.parametrize("clamping_mode", ("soft", "hard", None))
55305530
@pytest.mark.parametrize("dtype", [torch.int64, torch.float32])
55315531
@pytest.mark.parametrize("device", cpu_and_cuda())
55325532
def test_kernel(self, format, clamping_mode, dtype, device):
@@ -5542,7 +5542,7 @@ def test_kernel(self, format, clamping_mode, dtype, device):
55425542
)
55435543

55445544
@pytest.mark.parametrize("format", list(tv_tensors.BoundingBoxFormat))
5545-
@pytest.mark.parametrize("clamping_mode", ("hard", None)) # TODOBB add soft
5545+
@pytest.mark.parametrize("clamping_mode", ("soft", "hard", None))
55465546
def test_functional(self, format, clamping_mode):
55475547
check_functional(F.clamp_bounding_boxes, make_bounding_boxes(format=format, clamping_mode=clamping_mode))
55485548

@@ -5566,12 +5566,17 @@ def test_errors(self):
55665566
):
55675567
F.clamp_bounding_boxes(input_tv_tensor, format=format_, canvas_size=canvas_size_)
55685568

5569+
with pytest.raises(ValueError, match="clamping_mode must be soft,"):
5570+
F.clamp_bounding_boxes(input_tv_tensor, clamping_mode="bad")
5571+
with pytest.raises(ValueError, match="clamping_mode must be soft,"):
5572+
transforms.ClampBoundingBoxes(clamping_mode="bad")(input_tv_tensor)
5573+
55695574
def test_transform(self):
55705575
check_transform(transforms.ClampBoundingBoxes(), make_bounding_boxes())
55715576

55725577
@pytest.mark.parametrize("rotated", (True, False))
5573-
@pytest.mark.parametrize("constructor_clamping_mode", ("hard", None))
5574-
@pytest.mark.parametrize("clamping_mode", ("hard", None, "auto")) # TODOBB add soft here.
5578+
@pytest.mark.parametrize("constructor_clamping_mode", ("soft", "hard", None))
5579+
@pytest.mark.parametrize("clamping_mode", ("soft", "hard", None, "auto"))
55755580
@pytest.mark.parametrize("pass_pure_tensor", (True, False))
55765581
@pytest.mark.parametrize("fn", [F.clamp_bounding_boxes, transform_cls_to_functional(transforms.ClampBoundingBoxes)])
55775582
def test_clamping_mode(self, rotated, constructor_clamping_mode, clamping_mode, pass_pure_tensor, fn):
@@ -5624,8 +5629,8 @@ def test_clamping_mode(self, rotated, constructor_clamping_mode, clamping_mode,
56245629

56255630
class TestSetClampingMode:
56265631
@pytest.mark.parametrize("format", list(tv_tensors.BoundingBoxFormat))
5627-
@pytest.mark.parametrize("constructor_clamping_mode", ("hard", None)) # TODOBB add soft
5628-
@pytest.mark.parametrize("desired_clamping_mode", ("hard", None)) # TODOBB add soft
5632+
@pytest.mark.parametrize("constructor_clamping_mode", ("soft", "hard", None))
5633+
@pytest.mark.parametrize("desired_clamping_mode", ("soft", "hard", None))
56295634
def test_setter(self, format, constructor_clamping_mode, desired_clamping_mode):
56305635

56315636
in_boxes = make_bounding_boxes(format=format, clamping_mode=constructor_clamping_mode)
@@ -5635,7 +5640,7 @@ def test_setter(self, format, constructor_clamping_mode, desired_clamping_mode):
56355640
assert out_boxes.clamping_mode == desired_clamping_mode
56365641

56375642
@pytest.mark.parametrize("format", list(tv_tensors.BoundingBoxFormat))
5638-
@pytest.mark.parametrize("constructor_clamping_mode", ("hard", None)) # TODOBB add soft
5643+
@pytest.mark.parametrize("constructor_clamping_mode", ("soft", "hard", None))
56395644
def test_pipeline_no_leak(self, format, constructor_clamping_mode):
56405645
class AssertClampingMode(transforms.Transform):
56415646
def __init__(self, expected_clamping_mode):
@@ -5669,6 +5674,10 @@ def transform(self, inpt, _):
56695674
# ClampBoundingBoxes doesn't set clamping_mode.
56705675
assert out_boxes.clamping_mode is None
56715676

5677+
def test_error(self):
5678+
with pytest.raises(ValueError, match="clamping_mode must be"):
5679+
transforms.SetClampingMode("bad")
5680+
56725681

56735682
class TestClampKeyPoints:
56745683
@pytest.mark.parametrize("dtype", [torch.int64, torch.float32])

test/test_tv_tensors.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,11 +432,14 @@ def test_return_type_input():
432432
tv_tensors.set_return_type("tensor")
433433

434434

435-
def test_box_clamping_mode_default():
435+
def test_box_clamping_mode_default_and_error():
436436
assert (
437437
tv_tensors.BoundingBoxes([0.0, 0.0, 10.0, 10.0], format="XYXY", canvas_size=(100, 100)).clamping_mode == "soft"
438438
)
439439
assert (
440440
tv_tensors.BoundingBoxes([0.0, 0.0, 10.0, 10.0, 0.0], format="XYWHR", canvas_size=(100, 100)).clamping_mode
441441
== "soft"
442442
)
443+
444+
with pytest.raises(ValueError, match="clamping_mode must be"):
445+
tv_tensors.BoundingBoxes([0, 0, 10, 10], format="XYXY", canvas_size=(100, 100), clamping_mode="bad")

test/test_utils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,17 @@ def test_draw_rotated_boxes():
177177
assert_equal(result, expected)
178178

179179

180+
@pytest.mark.skipif(PILLOW_VERSION < (10, 1), reason="The reference image is only valid for PIL >= 10.1")
181+
def test_draw_rotated_boxes_fill():
182+
img = torch.full((3, 500, 500), 255, dtype=torch.uint8)
183+
colors = ["blue", "yellow", (0, 255, 0), "black"]
184+
185+
result = utils.draw_bounding_boxes(img, rotated_boxes, colors=colors, fill=True)
186+
path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", "fakedata", "draw_rotated_boxes_fill.png")
187+
expected = torch.as_tensor(np.array(Image.open(path))).permute(2, 0, 1)
188+
assert_equal(result, expected)
189+
190+
180191
@pytest.mark.parametrize("fill", [True, False])
181192
def test_draw_boxes_dtypes(fill):
182193
img_uint8 = torch.full((3, 100, 100), 255, dtype=torch.uint8)

torchvision/transforms/v2/_meta.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ class ClampBoundingBoxes(Transform):
3434
3535
"""
3636

37-
# TODOBB consider "auto" to be a Literal, make sur torchscript is still happy
38-
# TODOBB validate clamping_mode
3937
def __init__(self, clamping_mode: Union[CLAMPING_MODE_TYPE, str] = "auto") -> None:
4038
super().__init__()
4139
self.clamping_mode = clamping_mode
@@ -63,9 +61,11 @@ class SetClampingMode(Transform):
6361

6462
def __init__(self, clamping_mode: CLAMPING_MODE_TYPE) -> None:
6563
super().__init__()
66-
# TODOBB validate mode
6764
self.clamping_mode = clamping_mode
6865

66+
if self.clamping_mode not in (None, "soft", "hard"):
67+
raise ValueError(f"clamping_mode must be soft, hard or None, got {clamping_mode}")
68+
6969
_transformed_types = (tv_tensors.BoundingBoxes,)
7070

7171
def transform(self, inpt: tv_tensors.BoundingBoxes, params: dict[str, Any]) -> tv_tensors.BoundingBoxes:

torchvision/transforms/v2/functional/_meta.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,9 @@ def clamp_bounding_boxes(
640640
if not torch.jit.is_scripting():
641641
_log_api_usage_once(clamp_bounding_boxes)
642642

643+
if clamping_mode is not None and clamping_mode not in ("soft", "hard", "auto"):
644+
raise ValueError(f"clamping_mode must be soft, hard, auto or None, got {clamping_mode}")
645+
643646
if torch.jit.is_scripting() or is_pure_tensor(inpt):
644647

645648
if format is None or canvas_size is None or (clamping_mode is not None and clamping_mode == "auto"):

torchvision/tv_tensors/_bounding_boxes.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,20 @@ class BoundingBoxFormat(Enum):
1616
1717
Available formats are:
1818
19-
* ``XYXY``
20-
* ``XYWH``
21-
* ``CXCYWH``
22-
* ``XYWHR``: rotated boxes represented via corner, width and height, x1, y1
23-
being top left, w, h being width and height. r is rotation angle in
19+
* ``XYXY``: bounding box represented via corners; x1, y1 being top left;
20+
x2, y2 being bottom right.
21+
* ``XYWH``: bounding box represented via corner, width and height; x1, y1
22+
being top left; w, h being width and height.
23+
* ``CXCYWH``: bounding box represented via centre, width and height; cx,
24+
cy being center of box; w, h being width and height.
25+
* ``XYWHR``: rotated boxes represented via corner, width and height; x1, y1
26+
being top left; w, h being width and height. r is rotation angle in
2427
degrees.
25-
* ``CXCYWHR``: rotated boxes represented via centre, width and height, cx,
26-
cy being center of box, w, h being width and height. r is rotation angle
28+
* ``CXCYWHR``: rotated boxes represented via center, width and height; cx,
29+
cy being center of box; w, h being width and height. r is rotation angle
2730
in degrees.
28-
* ``XYXYXYXY``: rotated boxes represented via corners, x1, y1 being top
29-
left, x2, y2 being top right, x3, y3 being bottom right, x4, y4 being
31+
* ``XYXYXYXY``: rotated boxes represented via corners; x1, y1 being top
32+
left; x2, y2 being top right; x3, y3 being bottom right; x4, y4 being
3033
bottom left.
3134
"""
3235

@@ -53,8 +56,7 @@ def is_rotated_bounding_format(format: BoundingBoxFormat | str) -> bool:
5356
raise ValueError(f"format should be str or BoundingBoxFormat, got {type(format)}")
5457

5558

56-
# TODOBB consider making this a Literal instead. Tried briefly and got
57-
# torchscript errors, leaving to str for now.
59+
# This should ideally be a Literal, but torchscript fails.
5860
CLAMPING_MODE_TYPE = Optional[str]
5961

6062
# TODOBB All docs. Add any new API to rst files, add tutorial[s].
@@ -96,12 +98,15 @@ def _wrap(cls, tensor: torch.Tensor, *, format: BoundingBoxFormat | str, canvas_
9698
tensor = tensor.unsqueeze(0)
9799
elif tensor.ndim != 2:
98100
raise ValueError(f"Expected a 1D or 2D tensor, got {tensor.ndim}D")
101+
if clamping_mode is not None and clamping_mode not in ("hard", "soft"):
102+
raise ValueError(f"clamping_mode must be None, hard or soft, got {clamping_mode}.")
103+
99104
if isinstance(format, str):
100105
format = BoundingBoxFormat[format.upper()]
106+
101107
bounding_boxes = tensor.as_subclass(cls)
102108
bounding_boxes.format = format
103109
bounding_boxes.canvas_size = canvas_size
104-
# TODOBB validate values
105110
bounding_boxes.clamping_mode = clamping_mode
106111
return bounding_boxes
107112

torchvision/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def oriented_rectangle(self, xy, fill=None, outline=None, width=1):
136136
width=width,
137137
fill=outline,
138138
)
139-
self.rectangle(xy, fill=fill, outline=None, width=0)
139+
self.polygon(xy, fill=fill, outline=None, width=0)
140140

141141
def dashed_line(self, xy, fill=None, width=0, joint=None, dash_length=5, space_length=5):
142142
# Calculate the total length of the line

version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.23.0a0
1+
0.24.0a0

0 commit comments

Comments
 (0)