4949from torchvision .transforms .functional import pil_modes_mapping , to_pil_image
5050from torchvision .transforms .v2 import functional as F
5151from torchvision .transforms .v2 ._utils import check_type , is_pure_tensor
52- from torchvision .transforms .v2 .functional ._geometry import _get_perspective_coeffs
52+ from torchvision .transforms .v2 .functional ._geometry import _get_perspective_coeffs , _parallelogram_to_bounding_boxes
5353from torchvision .transforms .v2 .functional ._utils import _get_kernel , _register_kernel_internal
5454
5555
@@ -560,7 +560,9 @@ def affine_bounding_boxes(bounding_boxes):
560560 )
561561
562562
563- def reference_affine_rotated_bounding_boxes_helper (bounding_boxes , * , affine_matrix , new_canvas_size = None , clamp = True ):
563+ def reference_affine_rotated_bounding_boxes_helper (
564+ bounding_boxes , * , affine_matrix , new_canvas_size = None , clamp = True , flip = False
565+ ):
564566 format = bounding_boxes .format
565567 canvas_size = new_canvas_size or bounding_boxes .canvas_size
566568
@@ -588,17 +590,20 @@ def affine_rotated_bounding_boxes(bounding_boxes):
588590 transformed_points = np .matmul (points , affine_matrix .astype (points .dtype ).T )
589591 output = torch .tensor (
590592 [
591- float (transformed_points [1 , 0 ]),
592- float (transformed_points [1 , 1 ]),
593593 float (transformed_points [0 , 0 ]),
594594 float (transformed_points [0 , 1 ]),
595- float (transformed_points [3 , 0 ]),
596- float (transformed_points [3 , 1 ]),
595+ float (transformed_points [1 , 0 ]),
596+ float (transformed_points [1 , 1 ]),
597597 float (transformed_points [2 , 0 ]),
598598 float (transformed_points [2 , 1 ]),
599+ float (transformed_points [3 , 0 ]),
600+ float (transformed_points [3 , 1 ]),
599601 ]
600602 )
601603
604+ output = output [[2 , 3 , 0 , 1 , 6 , 7 , 4 , 5 ]] if flip else output
605+ output = _parallelogram_to_bounding_boxes (output )
606+
602607 output = F .convert_bounding_box_format (
603608 output , old_format = tv_tensors .BoundingBoxFormat .XYXYXYXY , new_format = format
604609 )
@@ -707,7 +712,7 @@ def test_kernel_image(self, size, interpolation, use_max_size, antialias, dtype,
707712 check_scripted_vs_eager = not isinstance (size , int ),
708713 )
709714
710- @pytest .mark .parametrize ("format" , SUPPORTED_BOX_FORMATS )
715+ @pytest .mark .parametrize ("format" , list ( tv_tensors . BoundingBoxFormat ) )
711716 @pytest .mark .parametrize ("size" , OUTPUT_SIZES )
712717 @pytest .mark .parametrize ("use_max_size" , [True , False ])
713718 @pytest .mark .parametrize ("dtype" , [torch .float32 , torch .int64 ])
@@ -725,6 +730,7 @@ def test_kernel_bounding_boxes(self, format, size, use_max_size, dtype, device):
725730 check_kernel (
726731 F .resize_bounding_boxes ,
727732 bounding_boxes ,
733+ format = format ,
728734 canvas_size = bounding_boxes .canvas_size ,
729735 size = size ,
730736 ** max_size_kwarg ,
@@ -816,7 +822,7 @@ def test_image_correctness(self, size, interpolation, use_max_size, fn):
816822 self ._check_output_size (image , actual , size = size , ** max_size_kwarg )
817823 torch .testing .assert_close (actual , expected , atol = 1 , rtol = 0 )
818824
819- def _reference_resize_bounding_boxes (self , bounding_boxes , * , size , max_size = None ):
825+ def _reference_resize_bounding_boxes (self , bounding_boxes , format , * , size , max_size = None ):
820826 old_height , old_width = bounding_boxes .canvas_size
821827 new_height , new_width = self ._compute_output_size (
822828 input_size = bounding_boxes .canvas_size , size = size , max_size = max_size
@@ -832,13 +838,19 @@ def _reference_resize_bounding_boxes(self, bounding_boxes, *, size, max_size=Non
832838 ],
833839 )
834840
835- return reference_affine_bounding_boxes_helper (
841+ helper = (
842+ reference_affine_rotated_bounding_boxes_helper
843+ if tv_tensors .is_rotated_bounding_format (bounding_boxes .format )
844+ else reference_affine_bounding_boxes_helper
845+ )
846+
847+ return helper (
836848 bounding_boxes ,
837849 affine_matrix = affine_matrix ,
838850 new_canvas_size = (new_height , new_width ),
839851 )
840852
841- @pytest .mark .parametrize ("format" , SUPPORTED_BOX_FORMATS )
853+ @pytest .mark .parametrize ("format" , list ( tv_tensors . BoundingBoxFormat ) )
842854 @pytest .mark .parametrize ("size" , OUTPUT_SIZES )
843855 @pytest .mark .parametrize ("use_max_size" , [True , False ])
844856 @pytest .mark .parametrize ("fn" , [F .resize , transform_cls_to_functional (transforms .Resize )])
@@ -849,7 +861,7 @@ def test_bounding_boxes_correctness(self, format, size, use_max_size, fn):
849861 bounding_boxes = make_bounding_boxes (format = format , canvas_size = self .INPUT_SIZE )
850862
851863 actual = fn (bounding_boxes , size = size , ** max_size_kwarg )
852- expected = self ._reference_resize_bounding_boxes (bounding_boxes , size = size , ** max_size_kwarg )
864+ expected = self ._reference_resize_bounding_boxes (bounding_boxes , format = format , size = size , ** max_size_kwarg )
853865
854866 self ._check_output_size (bounding_boxes , actual , size = size , ** max_size_kwarg )
855867 torch .testing .assert_close (actual , expected )
@@ -1152,7 +1164,7 @@ def _reference_horizontal_flip_bounding_boxes(self, bounding_boxes: tv_tensors.B
11521164 )
11531165
11541166 helper = (
1155- reference_affine_rotated_bounding_boxes_helper
1167+ functools . partial ( reference_affine_rotated_bounding_boxes_helper , flip = True )
11561168 if tv_tensors .is_rotated_bounding_format (bounding_boxes .format )
11571169 else reference_affine_bounding_boxes_helper
11581170 )
@@ -1607,7 +1619,7 @@ def _reference_vertical_flip_bounding_boxes(self, bounding_boxes: tv_tensors.Bou
16071619 )
16081620
16091621 helper = (
1610- reference_affine_rotated_bounding_boxes_helper
1622+ functools . partial ( reference_affine_rotated_bounding_boxes_helper , flip = True )
16111623 if tv_tensors .is_rotated_bounding_format (bounding_boxes .format )
16121624 else reference_affine_bounding_boxes_helper
16131625 )
0 commit comments