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
55088157
Commit
55088157
authored
Jul 03, 2019
by
ptrblck
Committed by
Francisco Massa
Jul 03, 2019
Browse files
Add shear parallel to y-axis (#1070)
* initial commit * add more checks, fix lint, fix doc
parent
8350645b
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
48 additions
and
23 deletions
+48
-23
test/test_transforms.py
test/test_transforms.py
+12
-10
torchvision/transforms/functional.py
torchvision/transforms/functional.py
+18
-7
torchvision/transforms/transforms.py
torchvision/transforms/transforms.py
+18
-6
No files found.
test/test_transforms.py
View file @
55088157
...
@@ -1087,15 +1087,15 @@ class Tester(unittest.TestCase):
...
@@ -1087,15 +1087,15 @@ class Tester(unittest.TestCase):
def
_test_transformation
(
a
,
t
,
s
,
sh
):
def
_test_transformation
(
a
,
t
,
s
,
sh
):
a_rad
=
math
.
radians
(
a
)
a_rad
=
math
.
radians
(
a
)
s_rad
=
math
.
radians
(
sh
)
s_rad
=
[
math
.
radians
(
sh
_
)
for
sh_
in
sh
]
# 1) Check transformation matrix:
# 1) Check transformation matrix:
c_matrix
=
np
.
array
([[
1.0
,
0.0
,
cnt
[
0
]],
[
0.0
,
1.0
,
cnt
[
1
]],
[
0.0
,
0.0
,
1.0
]])
c_matrix
=
np
.
array
([[
1.0
,
0.0
,
cnt
[
0
]],
[
0.0
,
1.0
,
cnt
[
1
]],
[
0.0
,
0.0
,
1.0
]])
c_inv_matrix
=
np
.
linalg
.
inv
(
c_matrix
)
c_inv_matrix
=
np
.
linalg
.
inv
(
c_matrix
)
t_matrix
=
np
.
array
([[
1.0
,
0.0
,
t
[
0
]],
t_matrix
=
np
.
array
([[
1.0
,
0.0
,
t
[
0
]],
[
0.0
,
1.0
,
t
[
1
]],
[
0.0
,
1.0
,
t
[
1
]],
[
0.0
,
0.0
,
1.0
]])
[
0.0
,
0.0
,
1.0
]])
r_matrix
=
np
.
array
([[
s
*
math
.
cos
(
a_rad
),
-
s
*
math
.
sin
(
a_rad
+
s_rad
),
0.0
],
r_matrix
=
np
.
array
([[
s
*
math
.
cos
(
a_rad
+
s_rad
[
1
]
),
-
s
*
math
.
sin
(
a_rad
+
s_rad
[
0
]
),
0.0
],
[
s
*
math
.
sin
(
a_rad
),
s
*
math
.
cos
(
a_rad
+
s_rad
),
0.0
],
[
s
*
math
.
sin
(
a_rad
+
s_rad
[
1
]
),
s
*
math
.
cos
(
a_rad
+
s_rad
[
0
]
),
0.0
],
[
0.0
,
0.0
,
1.0
]])
[
0.0
,
0.0
,
1.0
]])
true_matrix
=
np
.
dot
(
t_matrix
,
np
.
dot
(
c_matrix
,
np
.
dot
(
r_matrix
,
c_inv_matrix
)))
true_matrix
=
np
.
dot
(
t_matrix
,
np
.
dot
(
c_matrix
,
np
.
dot
(
r_matrix
,
c_inv_matrix
)))
result_matrix
=
_to_3x3_inv
(
F
.
_get_inverse_affine_matrix
(
center
=
cnt
,
angle
=
a
,
result_matrix
=
_to_3x3_inv
(
F
.
_get_inverse_affine_matrix
(
center
=
cnt
,
angle
=
a
,
...
@@ -1124,18 +1124,18 @@ class Tester(unittest.TestCase):
...
@@ -1124,18 +1124,18 @@ class Tester(unittest.TestCase):
# Test rotation
# Test rotation
a
=
45
a
=
45
_test_transformation
(
a
=
a
,
t
=
(
0
,
0
),
s
=
1.0
,
sh
=
0.0
)
_test_transformation
(
a
=
a
,
t
=
(
0
,
0
),
s
=
1.0
,
sh
=
(
0.0
,
0.0
)
)
# Test translation
# Test translation
t
=
[
10
,
15
]
t
=
[
10
,
15
]
_test_transformation
(
a
=
0.0
,
t
=
t
,
s
=
1.0
,
sh
=
0.0
)
_test_transformation
(
a
=
0.0
,
t
=
t
,
s
=
1.0
,
sh
=
(
0.0
,
0.0
)
)
# Test scale
# Test scale
s
=
1.2
s
=
1.2
_test_transformation
(
a
=
0.0
,
t
=
(
0.0
,
0.0
),
s
=
s
,
sh
=
0.0
)
_test_transformation
(
a
=
0.0
,
t
=
(
0.0
,
0.0
),
s
=
s
,
sh
=
(
0.0
,
0.0
)
)
# Test shear
# Test shear
sh
=
45.0
sh
=
[
45.0
,
25.0
]
_test_transformation
(
a
=
0.0
,
t
=
(
0.0
,
0.0
),
s
=
1.0
,
sh
=
sh
)
_test_transformation
(
a
=
0.0
,
t
=
(
0.0
,
0.0
),
s
=
1.0
,
sh
=
sh
)
# Test rotation, scale, translation, shear
# Test rotation, scale, translation, shear
...
@@ -1143,7 +1143,7 @@ class Tester(unittest.TestCase):
...
@@ -1143,7 +1143,7 @@ class Tester(unittest.TestCase):
for
t1
in
range
(
-
10
,
10
,
5
):
for
t1
in
range
(
-
10
,
10
,
5
):
for
s
in
[
0.75
,
0.98
,
1.0
,
1.1
,
1.2
]:
for
s
in
[
0.75
,
0.98
,
1.0
,
1.1
,
1.2
]:
for
sh
in
range
(
-
15
,
15
,
5
):
for
sh
in
range
(
-
15
,
15
,
5
):
_test_transformation
(
a
=
a
,
t
=
(
t1
,
t1
),
s
=
s
,
sh
=
sh
)
_test_transformation
(
a
=
a
,
t
=
(
t1
,
t1
),
s
=
s
,
sh
=
(
sh
,
sh
)
)
def
test_random_rotation
(
self
):
def
test_random_rotation
(
self
):
...
@@ -1182,11 +1182,12 @@ class Tester(unittest.TestCase):
...
@@ -1182,11 +1182,12 @@ class Tester(unittest.TestCase):
transforms
.
RandomAffine
([
-
90
,
90
],
translate
=
[
0.2
,
0.2
],
scale
=
[
0.5
,
0.5
],
shear
=-
7
)
transforms
.
RandomAffine
([
-
90
,
90
],
translate
=
[
0.2
,
0.2
],
scale
=
[
0.5
,
0.5
],
shear
=-
7
)
transforms
.
RandomAffine
([
-
90
,
90
],
translate
=
[
0.2
,
0.2
],
scale
=
[
0.5
,
0.5
],
shear
=
[
-
10
])
transforms
.
RandomAffine
([
-
90
,
90
],
translate
=
[
0.2
,
0.2
],
scale
=
[
0.5
,
0.5
],
shear
=
[
-
10
])
transforms
.
RandomAffine
([
-
90
,
90
],
translate
=
[
0.2
,
0.2
],
scale
=
[
0.5
,
0.5
],
shear
=
[
-
10
,
0
,
10
])
transforms
.
RandomAffine
([
-
90
,
90
],
translate
=
[
0.2
,
0.2
],
scale
=
[
0.5
,
0.5
],
shear
=
[
-
10
,
0
,
10
])
transforms
.
RandomAffine
([
-
90
,
90
],
translate
=
[
0.2
,
0.2
],
scale
=
[
0.5
,
0.5
],
shear
=
[
-
10
,
0
,
10
,
0
,
10
])
x
=
np
.
zeros
((
100
,
100
,
3
),
dtype
=
np
.
uint8
)
x
=
np
.
zeros
((
100
,
100
,
3
),
dtype
=
np
.
uint8
)
img
=
F
.
to_pil_image
(
x
)
img
=
F
.
to_pil_image
(
x
)
t
=
transforms
.
RandomAffine
(
10
,
translate
=
[
0.5
,
0.3
],
scale
=
[
0.7
,
1.3
],
shear
=
[
-
10
,
10
])
t
=
transforms
.
RandomAffine
(
10
,
translate
=
[
0.5
,
0.3
],
scale
=
[
0.7
,
1.3
],
shear
=
[
-
10
,
10
,
20
,
40
])
for
_
in
range
(
100
):
for
_
in
range
(
100
):
angle
,
translations
,
scale
,
shear
=
t
.
get_params
(
t
.
degrees
,
t
.
translate
,
t
.
scale
,
t
.
shear
,
angle
,
translations
,
scale
,
shear
=
t
.
get_params
(
t
.
degrees
,
t
.
translate
,
t
.
scale
,
t
.
shear
,
img_size
=
img
.
size
)
img_size
=
img
.
size
)
...
@@ -1196,7 +1197,8 @@ class Tester(unittest.TestCase):
...
@@ -1196,7 +1197,8 @@ class Tester(unittest.TestCase):
assert
-
img
.
size
[
1
]
*
0.5
<=
translations
[
1
]
<=
img
.
size
[
1
]
*
0.5
,
\
assert
-
img
.
size
[
1
]
*
0.5
<=
translations
[
1
]
<=
img
.
size
[
1
]
*
0.5
,
\
"{} vs {}"
.
format
(
translations
[
1
],
img
.
size
[
1
]
*
0.5
)
"{} vs {}"
.
format
(
translations
[
1
],
img
.
size
[
1
]
*
0.5
)
assert
0.7
<
scale
<
1.3
assert
0.7
<
scale
<
1.3
assert
-
10
<
shear
<
10
assert
-
10
<
shear
[
0
]
<
10
assert
-
20
<
shear
[
1
]
<
40
# Checking if RandomAffine can be printed as string
# Checking if RandomAffine can be printed as string
t
.
__repr__
()
t
.
__repr__
()
...
...
torchvision/transforms/functional.py
View file @
55088157
...
@@ -722,20 +722,29 @@ def _get_inverse_affine_matrix(center, angle, translate, scale, shear):
...
@@ -722,20 +722,29 @@ def _get_inverse_affine_matrix(center, angle, translate, scale, shear):
# where T is translation matrix: [1, 0, tx | 0, 1, ty | 0, 0, 1]
# where T is translation matrix: [1, 0, tx | 0, 1, ty | 0, 0, 1]
# C is translation matrix to keep center: [1, 0, cx | 0, 1, cy | 0, 0, 1]
# C is translation matrix to keep center: [1, 0, cx | 0, 1, cy | 0, 0, 1]
# RSS is rotation with scale and shear matrix
# RSS is rotation with scale and shear matrix
# RSS(a, scale, shear) = [ cos(a)*scale -sin(a + shear)*scale 0]
# RSS(a, scale, shear) = [ cos(a
+ shear_y
)*scale -sin(a + shear
_x
)*scale 0]
# [ sin(a)*scale cos(a + shear)*scale 0]
# [ sin(a
+ shear_y
)*scale cos(a + shear
_x
)*scale 0]
# [ 0 0 1]
# [ 0 0 1]
# Thus, the inverse is M^-1 = C * RSS^-1 * C^-1 * T^-1
# Thus, the inverse is M^-1 = C * RSS^-1 * C^-1 * T^-1
angle
=
math
.
radians
(
angle
)
angle
=
math
.
radians
(
angle
)
shear
=
math
.
radians
(
shear
)
if
isinstance
(
shear
,
(
tuple
,
list
))
and
len
(
shear
)
==
2
:
shear
=
[
math
.
radians
(
s
)
for
s
in
shear
]
elif
isinstance
(
shear
,
numbers
.
Number
):
shear
=
math
.
radians
(
shear
)
shear
=
[
shear
,
0
]
else
:
raise
ValueError
(
"Shear should be a single value or a tuple/list containing "
+
"two values. Got {}"
.
format
(
shear
))
scale
=
1.0
/
scale
scale
=
1.0
/
scale
# Inverted rotation matrix with scale and shear
# Inverted rotation matrix with scale and shear
d
=
math
.
cos
(
angle
+
shear
)
*
math
.
cos
(
angle
)
+
math
.
sin
(
angle
+
shear
)
*
math
.
sin
(
angle
)
d
=
math
.
cos
(
angle
+
shear
[
0
])
*
math
.
cos
(
angle
+
shear
[
1
])
+
\
math
.
sin
(
angle
+
shear
[
0
])
*
math
.
sin
(
angle
+
shear
[
1
])
matrix
=
[
matrix
=
[
math
.
cos
(
angle
+
shear
),
math
.
sin
(
angle
+
shear
),
0
,
math
.
cos
(
angle
+
shear
[
0
]
),
math
.
sin
(
angle
+
shear
[
0
]
),
0
,
-
math
.
sin
(
angle
),
math
.
cos
(
angle
),
0
-
math
.
sin
(
angle
+
shear
[
1
]
),
math
.
cos
(
angle
+
shear
[
1
]
),
0
]
]
matrix
=
[
scale
/
d
*
m
for
m
in
matrix
]
matrix
=
[
scale
/
d
*
m
for
m
in
matrix
]
...
@@ -757,7 +766,9 @@ def affine(img, angle, translate, scale, shear, resample=0, fillcolor=None):
...
@@ -757,7 +766,9 @@ def affine(img, angle, translate, scale, shear, resample=0, fillcolor=None):
angle (float or int): rotation angle in degrees between -180 and 180, clockwise direction.
angle (float or int): rotation angle in degrees between -180 and 180, clockwise direction.
translate (list or tuple of integers): horizontal and vertical translations (post-rotation translation)
translate (list or tuple of integers): horizontal and vertical translations (post-rotation translation)
scale (float): overall scale
scale (float): overall scale
shear (float): shear angle value in degrees between -180 to 180, clockwise direction.
shear (float or tuple or list): shear angle value in degrees between -180 to 180, clockwise direction.
If a tuple of list is specified, the first value corresponds to a shear parallel to the x axis, while
the second value corresponds to a shear parallel to the y axis.
resample (``PIL.Image.NEAREST`` or ``PIL.Image.BILINEAR`` or ``PIL.Image.BICUBIC``, optional):
resample (``PIL.Image.NEAREST`` or ``PIL.Image.BILINEAR`` or ``PIL.Image.BICUBIC``, optional):
An optional resampling filter.
An optional resampling filter.
See `filters`_ for more information.
See `filters`_ for more information.
...
...
torchvision/transforms/transforms.py
View file @
55088157
...
@@ -1013,8 +1013,11 @@ class RandomAffine(object):
...
@@ -1013,8 +1013,11 @@ class RandomAffine(object):
scale (tuple, optional): scaling factor interval, e.g (a, b), then scale is
scale (tuple, optional): scaling factor interval, e.g (a, b), then scale is
randomly sampled from the range a <= scale <= b. Will keep original scale by default.
randomly sampled from the range a <= scale <= b. Will keep original scale by default.
shear (sequence or float or int, optional): Range of degrees to select from.
shear (sequence or float or int, optional): Range of degrees to select from.
If degrees is a number instead of sequence like (min, max), the range of degrees
If shear is a number, a shear parallel to the x axis in the range (-shear, +shear)
will be (-degrees, +degrees). Will not apply shear by default
will be apllied. Else if shear is a tuple or list of 2 values a shear parallel to the x axis in the
range (shear[0], shear[1]) will be applied. Else if shear is a tuple or list of 4 values,
a x-axis shear in (shear[0], shear[1]) and y-axis shear in (shear[2], shear[3]) will be applied.
Will not apply shear by default
resample ({PIL.Image.NEAREST, PIL.Image.BILINEAR, PIL.Image.BICUBIC}, optional):
resample ({PIL.Image.NEAREST, PIL.Image.BILINEAR, PIL.Image.BICUBIC}, optional):
An optional resampling filter. See `filters`_ for more information.
An optional resampling filter. See `filters`_ for more information.
If omitted, or if the image has mode "1" or "P", it is set to PIL.Image.NEAREST.
If omitted, or if the image has mode "1" or "P", it is set to PIL.Image.NEAREST.
...
@@ -1057,9 +1060,14 @@ class RandomAffine(object):
...
@@ -1057,9 +1060,14 @@ class RandomAffine(object):
raise
ValueError
(
"If shear is a single number, it must be positive."
)
raise
ValueError
(
"If shear is a single number, it must be positive."
)
self
.
shear
=
(
-
shear
,
shear
)
self
.
shear
=
(
-
shear
,
shear
)
else
:
else
:
assert
isinstance
(
shear
,
(
tuple
,
list
))
and
len
(
shear
)
==
2
,
\
assert
isinstance
(
shear
,
(
tuple
,
list
))
and
\
"shear should be a list or tuple and it must be of length 2."
(
len
(
shear
)
==
2
or
len
(
shear
)
==
4
),
\
self
.
shear
=
shear
"shear should be a list or tuple and it must be of length 2 or 4."
# X-Axis shear with [min, max]
if
len
(
shear
)
==
2
:
self
.
shear
=
[
shear
[
0
],
shear
[
1
],
0.
,
0.
]
elif
len
(
shear
)
==
4
:
self
.
shear
=
[
s
for
s
in
shear
]
else
:
else
:
self
.
shear
=
shear
self
.
shear
=
shear
...
@@ -1088,7 +1096,11 @@ class RandomAffine(object):
...
@@ -1088,7 +1096,11 @@ class RandomAffine(object):
scale
=
1.0
scale
=
1.0
if
shears
is
not
None
:
if
shears
is
not
None
:
shear
=
random
.
uniform
(
shears
[
0
],
shears
[
1
])
if
len
(
shears
)
==
2
:
shear
=
[
random
.
uniform
(
shears
[
0
],
shears
[
1
]),
0.
]
elif
len
(
shears
)
==
4
:
shear
=
[
random
.
uniform
(
shears
[
0
],
shears
[
1
]),
random
.
uniform
(
shears
[
2
],
shears
[
3
])]
else
:
else
:
shear
=
0.0
shear
=
0.0
...
...
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