Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
vision
Commits
a06df0d9
Unverified
Commit
a06df0d9
authored
Aug 30, 2023
by
Philip Meier
Committed by
GitHub
Aug 30, 2023
Browse files
add tests for F.crop and transforms.RandomCrop (#7892)
Co-authored-by:
Nicolas Hug
<
contact@nicolas-hug.com
>
parent
58f834a3
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
237 additions
and
254 deletions
+237
-254
test/test_transforms_v2.py
test/test_transforms_v2.py
+0
-62
test/test_transforms_v2_consistency.py
test/test_transforms_v2_consistency.py
+0
-21
test/test_transforms_v2_functional.py
test/test_transforms_v2_functional.py
+0
-57
test/test_transforms_v2_refactored.py
test/test_transforms_v2_refactored.py
+236
-4
test/transforms_v2_dispatcher_infos.py
test/transforms_v2_dispatcher_infos.py
+0
-10
test/transforms_v2_kernel_infos.py
test/transforms_v2_kernel_infos.py
+0
-99
torchvision/transforms/v2/functional/_geometry.py
torchvision/transforms/v2/functional/_geometry.py
+1
-1
No files found.
test/test_transforms_v2.py
View file @
a06df0d9
...
@@ -449,68 +449,6 @@ class TestRandomZoomOut:
...
@@ -449,68 +449,6 @@ class TestRandomZoomOut:
assert
0
<=
params
[
"padding"
][
3
]
<=
(
side_range
[
1
]
-
1
)
*
h
assert
0
<=
params
[
"padding"
][
3
]
<=
(
side_range
[
1
]
-
1
)
*
h
class
TestRandomCrop
:
def
test_assertions
(
self
):
with
pytest
.
raises
(
ValueError
,
match
=
"Please provide only two dimensions"
):
transforms
.
RandomCrop
([
10
,
12
,
14
])
with
pytest
.
raises
(
TypeError
,
match
=
"Got inappropriate padding arg"
):
transforms
.
RandomCrop
([
10
,
12
],
padding
=
"abc"
)
with
pytest
.
raises
(
ValueError
,
match
=
"Padding must be an int or a 1, 2, or 4"
):
transforms
.
RandomCrop
([
10
,
12
],
padding
=
[
-
0.7
,
0
,
0.7
])
with
pytest
.
raises
(
TypeError
,
match
=
"Got inappropriate fill arg"
):
transforms
.
RandomCrop
([
10
,
12
],
padding
=
1
,
fill
=
"abc"
)
with
pytest
.
raises
(
ValueError
,
match
=
"Padding mode should be either"
):
transforms
.
RandomCrop
([
10
,
12
],
padding
=
1
,
padding_mode
=
"abc"
)
@
pytest
.
mark
.
parametrize
(
"padding"
,
[
None
,
1
,
[
2
,
3
],
[
1
,
2
,
3
,
4
]])
@
pytest
.
mark
.
parametrize
(
"size, pad_if_needed"
,
[((
10
,
10
),
False
),
((
50
,
25
),
True
)])
def
test__get_params
(
self
,
padding
,
pad_if_needed
,
size
):
h
,
w
=
size
=
(
24
,
32
)
image
=
make_image
(
size
)
transform
=
transforms
.
RandomCrop
(
size
,
padding
=
padding
,
pad_if_needed
=
pad_if_needed
)
params
=
transform
.
_get_params
([
image
])
if
padding
is
not
None
:
if
isinstance
(
padding
,
int
):
pad_top
=
pad_bottom
=
pad_left
=
pad_right
=
padding
elif
isinstance
(
padding
,
list
)
and
len
(
padding
)
==
2
:
pad_left
=
pad_right
=
padding
[
0
]
pad_top
=
pad_bottom
=
padding
[
1
]
elif
isinstance
(
padding
,
list
)
and
len
(
padding
)
==
4
:
pad_left
,
pad_top
,
pad_right
,
pad_bottom
=
padding
h
+=
pad_top
+
pad_bottom
w
+=
pad_left
+
pad_right
else
:
pad_left
=
pad_right
=
pad_top
=
pad_bottom
=
0
if
pad_if_needed
:
if
w
<
size
[
1
]:
diff
=
size
[
1
]
-
w
pad_left
+=
diff
pad_right
+=
diff
w
+=
2
*
diff
if
h
<
size
[
0
]:
diff
=
size
[
0
]
-
h
pad_top
+=
diff
pad_bottom
+=
diff
h
+=
2
*
diff
padding
=
[
pad_left
,
pad_top
,
pad_right
,
pad_bottom
]
assert
0
<=
params
[
"top"
]
<=
h
-
size
[
0
]
+
1
assert
0
<=
params
[
"left"
]
<=
w
-
size
[
1
]
+
1
assert
params
[
"height"
]
==
size
[
0
]
assert
params
[
"width"
]
==
size
[
1
]
assert
params
[
"needs_pad"
]
is
any
(
padding
)
assert
params
[
"padding"
]
==
padding
class
TestGaussianBlur
:
class
TestGaussianBlur
:
def
test_assertions
(
self
):
def
test_assertions
(
self
):
with
pytest
.
raises
(
ValueError
,
match
=
"Kernel size should be a tuple/list of two integers"
):
with
pytest
.
raises
(
ValueError
,
match
=
"Kernel size should be a tuple/list of two integers"
):
...
...
test/test_transforms_v2_consistency.py
View file @
a06df0d9
...
@@ -318,26 +318,6 @@ CONSISTENCY_CONFIGS = [
...
@@ -318,26 +318,6 @@ CONSISTENCY_CONFIGS = [
],
],
closeness_kwargs
=
{
"rtol"
:
1e-5
,
"atol"
:
1e-5
},
closeness_kwargs
=
{
"rtol"
:
1e-5
,
"atol"
:
1e-5
},
),
),
ConsistencyConfig
(
v2_transforms
.
RandomCrop
,
legacy_transforms
.
RandomCrop
,
[
ArgsKwargs
(
12
),
ArgsKwargs
((
15
,
17
)),
NotScriptableArgsKwargs
(
11
,
padding
=
1
),
ArgsKwargs
(
11
,
padding
=
[
1
]),
ArgsKwargs
((
8
,
13
),
padding
=
(
2
,
3
)),
ArgsKwargs
((
14
,
9
),
padding
=
(
0
,
2
,
1
,
0
)),
ArgsKwargs
(
36
,
pad_if_needed
=
True
),
ArgsKwargs
((
7
,
8
),
fill
=
1
),
NotScriptableArgsKwargs
(
5
,
fill
=
(
1
,
2
,
3
)),
ArgsKwargs
(
12
),
NotScriptableArgsKwargs
(
15
,
padding
=
2
,
padding_mode
=
"edge"
),
ArgsKwargs
(
17
,
padding
=
(
1
,
0
),
padding_mode
=
"reflect"
),
ArgsKwargs
(
8
,
padding
=
(
3
,
0
,
0
,
1
),
padding_mode
=
"symmetric"
),
],
make_images_kwargs
=
dict
(
DEFAULT_MAKE_IMAGES_KWARGS
,
sizes
=
[(
26
,
26
),
(
18
,
33
),
(
29
,
22
)]),
),
ConsistencyConfig
(
ConsistencyConfig
(
v2_transforms
.
RandomPerspective
,
v2_transforms
.
RandomPerspective
,
legacy_transforms
.
RandomPerspective
,
legacy_transforms
.
RandomPerspective
,
...
@@ -573,7 +553,6 @@ get_params_parametrization = pytest.mark.parametrize(
...
@@ -573,7 +553,6 @@ get_params_parametrization = pytest.mark.parametrize(
(
v2_transforms
.
RandomErasing
,
ArgsKwargs
(
make_image
(),
scale
=
(
0.3
,
0.7
),
ratio
=
(
0.5
,
1.5
))),
(
v2_transforms
.
RandomErasing
,
ArgsKwargs
(
make_image
(),
scale
=
(
0.3
,
0.7
),
ratio
=
(
0.5
,
1.5
))),
(
v2_transforms
.
ColorJitter
,
ArgsKwargs
(
brightness
=
None
,
contrast
=
None
,
saturation
=
None
,
hue
=
None
)),
(
v2_transforms
.
ColorJitter
,
ArgsKwargs
(
brightness
=
None
,
contrast
=
None
,
saturation
=
None
,
hue
=
None
)),
(
v2_transforms
.
GaussianBlur
,
ArgsKwargs
(
0.3
,
1.4
)),
(
v2_transforms
.
GaussianBlur
,
ArgsKwargs
(
0.3
,
1.4
)),
(
v2_transforms
.
RandomCrop
,
ArgsKwargs
(
make_image
(
size
=
(
61
,
47
)),
output_size
=
(
19
,
25
))),
(
v2_transforms
.
RandomPerspective
,
ArgsKwargs
(
23
,
17
,
0.5
)),
(
v2_transforms
.
RandomPerspective
,
ArgsKwargs
(
23
,
17
,
0.5
)),
(
v2_transforms
.
AutoAugment
,
ArgsKwargs
(
5
)),
(
v2_transforms
.
AutoAugment
,
ArgsKwargs
(
5
)),
]
]
...
...
test/test_transforms_v2_functional.py
View file @
a06df0d9
...
@@ -576,63 +576,6 @@ def _compute_affine_matrix(angle_, translate_, scale_, shear_, center_):
...
@@ -576,63 +576,6 @@ def _compute_affine_matrix(angle_, translate_, scale_, shear_, center_):
return
true_matrix
return
true_matrix
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
@
pytest
.
mark
.
parametrize
(
"format"
,
[
tv_tensors
.
BoundingBoxFormat
.
XYXY
,
tv_tensors
.
BoundingBoxFormat
.
XYWH
,
tv_tensors
.
BoundingBoxFormat
.
CXCYWH
],
)
@
pytest
.
mark
.
parametrize
(
"top, left, height, width, expected_bboxes"
,
[
[
8
,
12
,
30
,
40
,
[(
-
2.0
,
7.0
,
13.0
,
27.0
),
(
38.0
,
-
3.0
,
58.0
,
14.0
),
(
33.0
,
38.0
,
44.0
,
54.0
)]],
[
-
8
,
12
,
70
,
40
,
[(
-
2.0
,
23.0
,
13.0
,
43.0
),
(
38.0
,
13.0
,
58.0
,
30.0
),
(
33.0
,
54.0
,
44.0
,
70.0
)]],
],
)
def
test_correctness_crop_bounding_boxes
(
device
,
format
,
top
,
left
,
height
,
width
,
expected_bboxes
):
# Expected bboxes computed using Albumentations:
# import numpy as np
# from albumentations.augmentations.crops.functional import crop_bbox_by_coords, normalize_bbox, denormalize_bbox
# expected_bboxes = []
# for in_box in in_boxes:
# n_in_box = normalize_bbox(in_box, *size)
# n_out_box = crop_bbox_by_coords(
# n_in_box, (left, top, left + width, top + height), height, width, *size
# )
# out_box = denormalize_bbox(n_out_box, height, width)
# expected_bboxes.append(out_box)
format
=
tv_tensors
.
BoundingBoxFormat
.
XYXY
canvas_size
=
(
64
,
76
)
in_boxes
=
[
[
10.0
,
15.0
,
25.0
,
35.0
],
[
50.0
,
5.0
,
70.0
,
22.0
],
[
45.0
,
46.0
,
56.0
,
62.0
],
]
in_boxes
=
torch
.
tensor
(
in_boxes
,
device
=
device
)
if
format
!=
tv_tensors
.
BoundingBoxFormat
.
XYXY
:
in_boxes
=
convert_bounding_box_format
(
in_boxes
,
tv_tensors
.
BoundingBoxFormat
.
XYXY
,
format
)
expected_bboxes
=
clamp_bounding_boxes
(
tv_tensors
.
BoundingBoxes
(
expected_bboxes
,
format
=
"XYXY"
,
canvas_size
=
canvas_size
)
).
tolist
()
output_boxes
,
output_canvas_size
=
F
.
crop_bounding_boxes
(
in_boxes
,
format
,
top
,
left
,
canvas_size
[
0
],
canvas_size
[
1
],
)
if
format
!=
tv_tensors
.
BoundingBoxFormat
.
XYXY
:
output_boxes
=
convert_bounding_box_format
(
output_boxes
,
format
,
tv_tensors
.
BoundingBoxFormat
.
XYXY
)
torch
.
testing
.
assert_close
(
output_boxes
.
tolist
(),
expected_bboxes
)
torch
.
testing
.
assert_close
(
output_canvas_size
,
canvas_size
)
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
def
test_correctness_vertical_flip_segmentation_mask_on_fixed_input
(
device
):
def
test_correctness_vertical_flip_segmentation_mask_on_fixed_input
(
device
):
mask
=
torch
.
zeros
((
3
,
3
,
3
),
dtype
=
torch
.
long
,
device
=
device
)
mask
=
torch
.
zeros
((
3
,
3
,
3
),
dtype
=
torch
.
long
,
device
=
device
)
...
...
test/test_transforms_v2_refactored.py
View file @
a06df0d9
...
@@ -228,7 +228,7 @@ def check_functional_kernel_signature_match(functional, *, kernel, input_type):
...
@@ -228,7 +228,7 @@ def check_functional_kernel_signature_match(functional, *, kernel, input_type):
assert
functional_param
==
kernel_param
assert
functional_param
==
kernel_param
def
_check_transform_v1_compatibility
(
transform
,
input
,
rtol
,
atol
):
def
_check_transform_v1_compatibility
(
transform
,
input
,
*
,
rtol
,
atol
):
"""If the transform defines the ``_v1_transform_cls`` attribute, checks if the transform has a public, static
"""If the transform defines the ``_v1_transform_cls`` attribute, checks if the transform has a public, static
``get_params`` method that is the v1 equivalent, the output is close to v1, is scriptable, and the scripted version
``get_params`` method that is the v1 equivalent, the output is close to v1, is scriptable, and the scripted version
can be called without error."""
can be called without error."""
...
@@ -357,10 +357,11 @@ def reference_affine_bounding_boxes_helper(bounding_boxes, *, affine_matrix, new
...
@@ -357,10 +357,11 @@ def reference_affine_bounding_boxes_helper(bounding_boxes, *, affine_matrix, new
def
affine_bounding_boxes
(
bounding_boxes
):
def
affine_bounding_boxes
(
bounding_boxes
):
dtype
=
bounding_boxes
.
dtype
dtype
=
bounding_boxes
.
dtype
device
=
bounding_boxes
.
device
# Go to float before converting to prevent precision loss in case of CXCYWH -> XYXY and W or H is 1
# Go to float before converting to prevent precision loss in case of CXCYWH -> XYXY and W or H is 1
input_xyxy
=
F
.
convert_bounding_box_format
(
input_xyxy
=
F
.
convert_bounding_box_format
(
bounding_boxes
.
to
(
torch
.
float64
,
copy
=
True
),
bounding_boxes
.
to
(
dtype
=
torch
.
float64
,
device
=
"cpu"
,
copy
=
True
),
old_format
=
format
,
old_format
=
format
,
new_format
=
tv_tensors
.
BoundingBoxFormat
.
XYXY
,
new_format
=
tv_tensors
.
BoundingBoxFormat
.
XYXY
,
inplace
=
True
,
inplace
=
True
,
...
@@ -396,9 +397,13 @@ def reference_affine_bounding_boxes_helper(bounding_boxes, *, affine_matrix, new
...
@@ -396,9 +397,13 @@ def reference_affine_bounding_boxes_helper(bounding_boxes, *, affine_matrix, new
output
,
output
,
format
=
format
,
format
=
format
,
canvas_size
=
canvas_size
,
canvas_size
=
canvas_size
,
).
to
(
dtype
)
)
else
:
# We leave the bounding box as float64 so the caller gets the full precision to perform any additional
# operation
dtype
=
output
.
dtype
return
output
return
output
.
to
(
dtype
=
dtype
,
device
=
device
)
return
tv_tensors
.
BoundingBoxes
(
return
tv_tensors
.
BoundingBoxes
(
torch
.
cat
([
affine_bounding_boxes
(
b
)
for
b
in
bounding_boxes
.
reshape
(
-
1
,
4
).
unbind
()],
dim
=
0
).
reshape
(
torch
.
cat
([
affine_bounding_boxes
(
b
)
for
b
in
bounding_boxes
.
reshape
(
-
1
,
4
).
unbind
()],
dim
=
0
).
reshape
(
...
@@ -2486,3 +2491,230 @@ class TestToPureTensor:
...
@@ -2486,3 +2491,230 @@ class TestToPureTensor:
assert
isinstance
(
out_value
,
torch
.
Tensor
)
and
not
isinstance
(
out_value
,
tv_tensors
.
TVTensor
)
assert
isinstance
(
out_value
,
torch
.
Tensor
)
and
not
isinstance
(
out_value
,
tv_tensors
.
TVTensor
)
else
:
else
:
assert
isinstance
(
out_value
,
type
(
input_value
))
assert
isinstance
(
out_value
,
type
(
input_value
))
class
TestCrop
:
INPUT_SIZE
=
(
21
,
11
)
CORRECTNESS_CROP_KWARGS
=
[
# center
dict
(
top
=
5
,
left
=
5
,
height
=
10
,
width
=
5
),
# larger than input, i.e. pad
dict
(
top
=-
5
,
left
=-
5
,
height
=
30
,
width
=
20
),
# sides: left, right, top, bottom
dict
(
top
=-
5
,
left
=-
5
,
height
=
30
,
width
=
10
),
dict
(
top
=-
5
,
left
=
5
,
height
=
30
,
width
=
10
),
dict
(
top
=-
5
,
left
=-
5
,
height
=
20
,
width
=
20
),
dict
(
top
=
5
,
left
=-
5
,
height
=
20
,
width
=
20
),
# corners: top-left, top-right, bottom-left, bottom-right
dict
(
top
=-
5
,
left
=-
5
,
height
=
20
,
width
=
10
),
dict
(
top
=-
5
,
left
=
5
,
height
=
20
,
width
=
10
),
dict
(
top
=
5
,
left
=-
5
,
height
=
20
,
width
=
10
),
dict
(
top
=
5
,
left
=
5
,
height
=
20
,
width
=
10
),
]
MINIMAL_CROP_KWARGS
=
CORRECTNESS_CROP_KWARGS
[
0
]
@
pytest
.
mark
.
parametrize
(
"kwargs"
,
CORRECTNESS_CROP_KWARGS
)
@
pytest
.
mark
.
parametrize
(
"dtype"
,
[
torch
.
uint8
,
torch
.
float32
])
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
def
test_kernel_image
(
self
,
kwargs
,
dtype
,
device
):
check_kernel
(
F
.
crop_image
,
make_image
(
self
.
INPUT_SIZE
,
dtype
=
dtype
,
device
=
device
),
**
kwargs
)
@
pytest
.
mark
.
parametrize
(
"kwargs"
,
CORRECTNESS_CROP_KWARGS
)
@
pytest
.
mark
.
parametrize
(
"format"
,
list
(
tv_tensors
.
BoundingBoxFormat
))
@
pytest
.
mark
.
parametrize
(
"dtype"
,
[
torch
.
float32
,
torch
.
int64
])
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
def
test_kernel_bounding_box
(
self
,
kwargs
,
format
,
dtype
,
device
):
bounding_boxes
=
make_bounding_boxes
(
self
.
INPUT_SIZE
,
format
=
format
,
dtype
=
dtype
,
device
=
device
)
check_kernel
(
F
.
crop_bounding_boxes
,
bounding_boxes
,
format
=
format
,
**
kwargs
)
@
pytest
.
mark
.
parametrize
(
"make_mask"
,
[
make_segmentation_mask
,
make_detection_mask
])
def
test_kernel_mask
(
self
,
make_mask
):
check_kernel
(
F
.
crop_mask
,
make_mask
(
self
.
INPUT_SIZE
),
**
self
.
MINIMAL_CROP_KWARGS
)
def
test_kernel_video
(
self
):
check_kernel
(
F
.
crop_video
,
make_video
(
self
.
INPUT_SIZE
),
**
self
.
MINIMAL_CROP_KWARGS
)
@
pytest
.
mark
.
parametrize
(
"make_input"
,
[
make_image_tensor
,
make_image_pil
,
make_image
,
make_bounding_boxes
,
make_segmentation_mask
,
make_video
],
)
def
test_functional
(
self
,
make_input
):
check_functional
(
F
.
crop
,
make_input
(
self
.
INPUT_SIZE
),
**
self
.
MINIMAL_CROP_KWARGS
)
@
pytest
.
mark
.
parametrize
(
(
"kernel"
,
"input_type"
),
[
(
F
.
crop_image
,
torch
.
Tensor
),
(
F
.
_crop_image_pil
,
PIL
.
Image
.
Image
),
(
F
.
crop_image
,
tv_tensors
.
Image
),
(
F
.
crop_bounding_boxes
,
tv_tensors
.
BoundingBoxes
),
(
F
.
crop_mask
,
tv_tensors
.
Mask
),
(
F
.
crop_video
,
tv_tensors
.
Video
),
],
)
def
test_functional_signature
(
self
,
kernel
,
input_type
):
check_functional_kernel_signature_match
(
F
.
crop
,
kernel
=
kernel
,
input_type
=
input_type
)
@
pytest
.
mark
.
parametrize
(
"kwargs"
,
CORRECTNESS_CROP_KWARGS
)
def
test_functional_image_correctness
(
self
,
kwargs
):
image
=
make_image
(
self
.
INPUT_SIZE
,
dtype
=
torch
.
uint8
,
device
=
"cpu"
)
actual
=
F
.
crop
(
image
,
**
kwargs
)
expected
=
F
.
to_image
(
F
.
crop
(
F
.
to_pil_image
(
image
),
**
kwargs
))
assert_equal
(
actual
,
expected
)
@
param_value_parametrization
(
size
=
[(
10
,
5
),
(
25
,
15
),
(
25
,
5
),
(
10
,
15
)],
fill
=
EXHAUSTIVE_TYPE_FILLS
,
)
@
pytest
.
mark
.
parametrize
(
"make_input"
,
[
make_image_tensor
,
make_image_pil
,
make_image
,
make_bounding_boxes
,
make_segmentation_mask
,
make_video
],
)
def
test_transform
(
self
,
param
,
value
,
make_input
):
input
=
make_input
(
self
.
INPUT_SIZE
)
kwargs
=
{
param
:
value
}
if
param
==
"fill"
:
# 1. size is required
# 2. the fill parameter only has an affect if we need padding
kwargs
[
"size"
]
=
[
s
+
4
for
s
in
self
.
INPUT_SIZE
]
if
isinstance
(
input
,
PIL
.
Image
.
Image
)
and
isinstance
(
value
,
(
tuple
,
list
))
and
len
(
value
)
==
1
:
pytest
.
xfail
(
"F._pad_image_pil does not support sequences of length 1 for fill."
)
if
isinstance
(
input
,
tv_tensors
.
Mask
)
and
isinstance
(
value
,
(
tuple
,
list
)):
pytest
.
skip
(
"F.pad_mask doesn't support non-scalar fill."
)
check_transform
(
transforms
.
RandomCrop
(
**
kwargs
,
pad_if_needed
=
True
),
input
,
check_v1_compatibility
=
param
!=
"fill"
or
isinstance
(
value
,
(
int
,
float
)),
)
@
pytest
.
mark
.
parametrize
(
"padding"
,
[
1
,
(
1
,
1
),
(
1
,
1
,
1
,
1
)])
def
test_transform_padding
(
self
,
padding
):
inpt
=
make_image
(
self
.
INPUT_SIZE
)
output_size
=
[
s
+
2
for
s
in
F
.
get_size
(
inpt
)]
transform
=
transforms
.
RandomCrop
(
output_size
,
padding
=
padding
)
output
=
transform
(
inpt
)
assert
F
.
get_size
(
output
)
==
output_size
@
pytest
.
mark
.
parametrize
(
"padding"
,
[
None
,
1
,
(
1
,
1
),
(
1
,
1
,
1
,
1
)])
def
test_transform_insufficient_padding
(
self
,
padding
):
inpt
=
make_image
(
self
.
INPUT_SIZE
)
output_size
=
[
s
+
3
for
s
in
F
.
get_size
(
inpt
)]
transform
=
transforms
.
RandomCrop
(
output_size
,
padding
=
padding
)
with
pytest
.
raises
(
ValueError
,
match
=
"larger than (padded )?input image size"
):
transform
(
inpt
)
def
test_transform_pad_if_needed
(
self
):
inpt
=
make_image
(
self
.
INPUT_SIZE
)
output_size
=
[
s
*
2
for
s
in
F
.
get_size
(
inpt
)]
transform
=
transforms
.
RandomCrop
(
output_size
,
pad_if_needed
=
True
)
output
=
transform
(
inpt
)
assert
F
.
get_size
(
output
)
==
output_size
@
param_value_parametrization
(
size
=
[(
10
,
5
),
(
25
,
15
),
(
25
,
5
),
(
10
,
15
)],
fill
=
CORRECTNESS_FILLS
,
padding_mode
=
[
"constant"
,
"edge"
,
"reflect"
,
"symmetric"
],
)
@
pytest
.
mark
.
parametrize
(
"seed"
,
list
(
range
(
5
)))
def
test_transform_image_correctness
(
self
,
param
,
value
,
seed
):
kwargs
=
{
param
:
value
}
if
param
!=
"size"
:
# 1. size is required
# 2. the fill / padding_mode parameters only have an affect if we need padding
kwargs
[
"size"
]
=
[
s
+
4
for
s
in
self
.
INPUT_SIZE
]
if
param
==
"fill"
:
kwargs
[
"fill"
]
=
adapt_fill
(
kwargs
[
"fill"
],
dtype
=
torch
.
uint8
)
transform
=
transforms
.
RandomCrop
(
pad_if_needed
=
True
,
**
kwargs
)
image
=
make_image
(
self
.
INPUT_SIZE
)
with
freeze_rng_state
():
torch
.
manual_seed
(
seed
)
actual
=
transform
(
image
)
torch
.
manual_seed
(
seed
)
expected
=
F
.
to_image
(
transform
(
F
.
to_pil_image
(
image
)))
assert_equal
(
actual
,
expected
)
def
_reference_crop_bounding_boxes
(
self
,
bounding_boxes
,
*
,
top
,
left
,
height
,
width
):
affine_matrix
=
np
.
array
(
[
[
1
,
0
,
-
left
],
[
0
,
1
,
-
top
],
],
)
return
reference_affine_bounding_boxes_helper
(
bounding_boxes
,
affine_matrix
=
affine_matrix
,
new_canvas_size
=
(
height
,
width
)
)
@
pytest
.
mark
.
parametrize
(
"kwargs"
,
CORRECTNESS_CROP_KWARGS
)
@
pytest
.
mark
.
parametrize
(
"format"
,
list
(
tv_tensors
.
BoundingBoxFormat
))
@
pytest
.
mark
.
parametrize
(
"dtype"
,
[
torch
.
float32
,
torch
.
int64
])
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
def
test_functional_bounding_box_correctness
(
self
,
kwargs
,
format
,
dtype
,
device
):
bounding_boxes
=
make_bounding_boxes
(
self
.
INPUT_SIZE
,
format
=
format
,
dtype
=
dtype
,
device
=
device
)
actual
=
F
.
crop
(
bounding_boxes
,
**
kwargs
)
expected
=
self
.
_reference_crop_bounding_boxes
(
bounding_boxes
,
**
kwargs
)
assert_equal
(
actual
,
expected
,
atol
=
1
,
rtol
=
0
)
assert_equal
(
F
.
get_size
(
actual
),
F
.
get_size
(
expected
))
@
pytest
.
mark
.
parametrize
(
"output_size"
,
[(
17
,
11
),
(
11
,
17
),
(
11
,
11
)])
@
pytest
.
mark
.
parametrize
(
"format"
,
list
(
tv_tensors
.
BoundingBoxFormat
))
@
pytest
.
mark
.
parametrize
(
"dtype"
,
[
torch
.
float32
,
torch
.
int64
])
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
@
pytest
.
mark
.
parametrize
(
"seed"
,
list
(
range
(
5
)))
def
test_transform_bounding_boxes_correctness
(
self
,
output_size
,
format
,
dtype
,
device
,
seed
):
input_size
=
[
s
*
2
for
s
in
output_size
]
bounding_boxes
=
make_bounding_boxes
(
input_size
,
format
=
format
,
dtype
=
dtype
,
device
=
device
)
transform
=
transforms
.
RandomCrop
(
output_size
)
with
freeze_rng_state
():
torch
.
manual_seed
(
seed
)
params
=
transform
.
_get_params
([
bounding_boxes
])
assert
not
params
.
pop
(
"needs_pad"
)
del
params
[
"padding"
]
assert
params
.
pop
(
"needs_crop"
)
torch
.
manual_seed
(
seed
)
actual
=
transform
(
bounding_boxes
)
expected
=
self
.
_reference_crop_bounding_boxes
(
bounding_boxes
,
**
params
)
assert_equal
(
actual
,
expected
)
assert_equal
(
F
.
get_size
(
actual
),
F
.
get_size
(
expected
))
def
test_errors
(
self
):
with
pytest
.
raises
(
ValueError
,
match
=
"Please provide only two dimensions"
):
transforms
.
RandomCrop
([
10
,
12
,
14
])
with
pytest
.
raises
(
TypeError
,
match
=
"Got inappropriate padding arg"
):
transforms
.
RandomCrop
([
10
,
12
],
padding
=
"abc"
)
with
pytest
.
raises
(
ValueError
,
match
=
"Padding must be an int or a 1, 2, or 4"
):
transforms
.
RandomCrop
([
10
,
12
],
padding
=
[
-
0.7
,
0
,
0.7
])
with
pytest
.
raises
(
TypeError
,
match
=
"Got inappropriate fill arg"
):
transforms
.
RandomCrop
([
10
,
12
],
padding
=
1
,
fill
=
"abc"
)
with
pytest
.
raises
(
ValueError
,
match
=
"Padding mode should be either"
):
transforms
.
RandomCrop
([
10
,
12
],
padding
=
1
,
padding_mode
=
"abc"
)
test/transforms_v2_dispatcher_infos.py
View file @
a06df0d9
...
@@ -139,16 +139,6 @@ xfails_pil_if_fill_sequence_needs_broadcast = xfails_pil(
...
@@ -139,16 +139,6 @@ xfails_pil_if_fill_sequence_needs_broadcast = xfails_pil(
DISPATCHER_INFOS
=
[
DISPATCHER_INFOS
=
[
DispatcherInfo
(
F
.
crop
,
kernels
=
{
tv_tensors
.
Image
:
F
.
crop_image
,
tv_tensors
.
Video
:
F
.
crop_video
,
tv_tensors
.
BoundingBoxes
:
F
.
crop_bounding_boxes
,
tv_tensors
.
Mask
:
F
.
crop_mask
,
},
pil_kernel_info
=
PILKernelInfo
(
F
.
_crop_image_pil
,
kernel_name
=
"crop_image_pil"
),
),
DispatcherInfo
(
DispatcherInfo
(
F
.
resized_crop
,
F
.
resized_crop
,
kernels
=
{
kernels
=
{
...
...
test/transforms_v2_kernel_infos.py
View file @
a06df0d9
...
@@ -259,105 +259,6 @@ KERNEL_INFOS.append(
...
@@ -259,105 +259,6 @@ KERNEL_INFOS.append(
)
)
_CROP_PARAMS
=
combinations_grid
(
top
=
[
-
8
,
0
,
9
],
left
=
[
-
8
,
0
,
9
],
height
=
[
12
,
20
],
width
=
[
12
,
20
])
def
sample_inputs_crop_image_tensor
():
for
image_loader
,
params
in
itertools
.
product
(
make_image_loaders
(
sizes
=
[(
16
,
17
)],
color_spaces
=
[
"RGB"
],
dtypes
=
[
torch
.
float32
]),
[
dict
(
top
=
4
,
left
=
3
,
height
=
7
,
width
=
8
),
dict
(
top
=-
1
,
left
=
3
,
height
=
7
,
width
=
8
),
dict
(
top
=
4
,
left
=-
1
,
height
=
7
,
width
=
8
),
dict
(
top
=
4
,
left
=
3
,
height
=
17
,
width
=
8
),
dict
(
top
=
4
,
left
=
3
,
height
=
7
,
width
=
18
),
],
):
yield
ArgsKwargs
(
image_loader
,
**
params
)
def
reference_inputs_crop_image_tensor
():
for
image_loader
,
params
in
itertools
.
product
(
make_image_loaders
(
extra_dims
=
[()],
dtypes
=
[
torch
.
uint8
]),
_CROP_PARAMS
):
yield
ArgsKwargs
(
image_loader
,
**
params
)
def
sample_inputs_crop_bounding_boxes
():
for
bounding_boxes_loader
,
params
in
itertools
.
product
(
make_bounding_box_loaders
(),
[
_CROP_PARAMS
[
0
],
_CROP_PARAMS
[
-
1
]]
):
yield
ArgsKwargs
(
bounding_boxes_loader
,
format
=
bounding_boxes_loader
.
format
,
**
params
)
def
sample_inputs_crop_mask
():
for
mask_loader
in
make_mask_loaders
(
sizes
=
[(
16
,
17
)],
num_categories
=
[
10
],
num_objects
=
[
5
]):
yield
ArgsKwargs
(
mask_loader
,
top
=
4
,
left
=
3
,
height
=
7
,
width
=
8
)
def
reference_inputs_crop_mask
():
for
mask_loader
,
params
in
itertools
.
product
(
make_mask_loaders
(
extra_dims
=
[()],
num_objects
=
[
1
]),
_CROP_PARAMS
):
yield
ArgsKwargs
(
mask_loader
,
**
params
)
def
sample_inputs_crop_video
():
for
video_loader
in
make_video_loaders
(
sizes
=
[(
16
,
17
)],
num_frames
=
[
3
]):
yield
ArgsKwargs
(
video_loader
,
top
=
4
,
left
=
3
,
height
=
7
,
width
=
8
)
def
reference_crop_bounding_boxes
(
bounding_boxes
,
*
,
format
,
top
,
left
,
height
,
width
):
affine_matrix
=
np
.
array
(
[
[
1
,
0
,
-
left
],
[
0
,
1
,
-
top
],
],
dtype
=
"float64"
if
bounding_boxes
.
dtype
==
torch
.
float64
else
"float32"
,
)
canvas_size
=
(
height
,
width
)
expected_bboxes
=
reference_affine_bounding_boxes_helper
(
bounding_boxes
,
format
=
format
,
canvas_size
=
canvas_size
,
affine_matrix
=
affine_matrix
)
return
expected_bboxes
,
canvas_size
def
reference_inputs_crop_bounding_boxes
():
for
bounding_boxes_loader
,
params
in
itertools
.
product
(
make_bounding_box_loaders
(
extra_dims
=
((),
(
4
,))),
[
_CROP_PARAMS
[
0
],
_CROP_PARAMS
[
-
1
]]
):
yield
ArgsKwargs
(
bounding_boxes_loader
,
format
=
bounding_boxes_loader
.
format
,
**
params
)
KERNEL_INFOS
.
extend
(
[
KernelInfo
(
F
.
crop_image
,
kernel_name
=
"crop_image_tensor"
,
sample_inputs_fn
=
sample_inputs_crop_image_tensor
,
reference_fn
=
pil_reference_wrapper
(
F
.
_crop_image_pil
),
reference_inputs_fn
=
reference_inputs_crop_image_tensor
,
float32_vs_uint8
=
True
,
),
KernelInfo
(
F
.
crop_bounding_boxes
,
sample_inputs_fn
=
sample_inputs_crop_bounding_boxes
,
reference_fn
=
reference_crop_bounding_boxes
,
reference_inputs_fn
=
reference_inputs_crop_bounding_boxes
,
),
KernelInfo
(
F
.
crop_mask
,
sample_inputs_fn
=
sample_inputs_crop_mask
,
reference_fn
=
pil_reference_wrapper
(
F
.
_crop_image_pil
),
reference_inputs_fn
=
reference_inputs_crop_mask
,
float32_vs_uint8
=
True
,
),
KernelInfo
(
F
.
crop_video
,
sample_inputs_fn
=
sample_inputs_crop_video
,
),
]
)
_RESIZED_CROP_PARAMS
=
combinations_grid
(
top
=
[
-
8
,
9
],
left
=
[
-
8
,
9
],
height
=
[
12
],
width
=
[
12
],
size
=
[(
16
,
18
)])
_RESIZED_CROP_PARAMS
=
combinations_grid
(
top
=
[
-
8
,
9
],
left
=
[
-
8
,
9
],
height
=
[
12
],
width
=
[
12
],
size
=
[(
16
,
18
)])
...
...
torchvision/transforms/v2/functional/_geometry.py
View file @
a06df0d9
...
@@ -1165,7 +1165,7 @@ def pad_image(
...
@@ -1165,7 +1165,7 @@ def pad_image(
fill
:
Optional
[
Union
[
int
,
float
,
List
[
float
]]]
=
None
,
fill
:
Optional
[
Union
[
int
,
float
,
List
[
float
]]]
=
None
,
padding_mode
:
str
=
"constant"
,
padding_mode
:
str
=
"constant"
,
)
->
torch
.
Tensor
:
)
->
torch
.
Tensor
:
# Be aware that while `padding` has order `[left, top, right, bottom]`
has order
, `torch_padding` uses
# Be aware that while `padding` has order `[left, top, right, bottom]`, `torch_padding` uses
# `[left, right, top, bottom]`. This stems from the fact that we align our API with PIL, but need to use `torch_pad`
# `[left, right, top, bottom]`. This stems from the fact that we align our API with PIL, but need to use `torch_pad`
# internally.
# internally.
torch_padding
=
_parse_pad_padding
(
padding
)
torch_padding
=
_parse_pad_padding
(
padding
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment