|
|
import pytest |
|
|
import torch |
|
|
from torch.autograd import gradcheck |
|
|
|
|
|
import kornia |
|
|
import kornia.testing as utils |
|
|
from kornia.testing import assert_close |
|
|
|
|
|
|
|
|
def identity_matrix(batch_size, device, dtype): |
|
|
r"""Create a batched homogeneous identity matrix""" |
|
|
return torch.eye(4, device=device, dtype=dtype).repeat(batch_size, 1, 1) |
|
|
|
|
|
|
|
|
def euler_angles_to_rotation_matrix(x, y, z): |
|
|
r"""Create a rotation matrix from x, y, z angles""" |
|
|
assert x.dim() == 1, x.shape |
|
|
assert x.shape == y.shape == z.shape |
|
|
ones, zeros = torch.ones_like(x), torch.zeros_like(x) |
|
|
|
|
|
rx_tmp = [ |
|
|
ones, |
|
|
zeros, |
|
|
zeros, |
|
|
zeros, |
|
|
zeros, |
|
|
torch.cos(x), |
|
|
-torch.sin(x), |
|
|
zeros, |
|
|
zeros, |
|
|
torch.sin(x), |
|
|
torch.cos(x), |
|
|
zeros, |
|
|
zeros, |
|
|
zeros, |
|
|
zeros, |
|
|
ones, |
|
|
] |
|
|
rx = torch.stack(rx_tmp, dim=-1).view(-1, 4, 4) |
|
|
|
|
|
ry_tmp = [ |
|
|
torch.cos(y), |
|
|
zeros, |
|
|
torch.sin(y), |
|
|
zeros, |
|
|
zeros, |
|
|
ones, |
|
|
zeros, |
|
|
zeros, |
|
|
-torch.sin(y), |
|
|
zeros, |
|
|
torch.cos(y), |
|
|
zeros, |
|
|
zeros, |
|
|
zeros, |
|
|
zeros, |
|
|
ones, |
|
|
] |
|
|
ry = torch.stack(ry_tmp, dim=-1).view(-1, 4, 4) |
|
|
|
|
|
rz_tmp = [ |
|
|
torch.cos(z), |
|
|
-torch.sin(z), |
|
|
zeros, |
|
|
zeros, |
|
|
torch.sin(z), |
|
|
torch.cos(z), |
|
|
zeros, |
|
|
zeros, |
|
|
zeros, |
|
|
zeros, |
|
|
ones, |
|
|
zeros, |
|
|
zeros, |
|
|
zeros, |
|
|
zeros, |
|
|
ones, |
|
|
] |
|
|
rz = torch.stack(rz_tmp, dim=-1).view(-1, 4, 4) |
|
|
return torch.matmul(rz, torch.matmul(ry, rx)) |
|
|
|
|
|
|
|
|
class TestTransformPoints: |
|
|
@pytest.mark.parametrize("batch_size", [1, 2, 5]) |
|
|
@pytest.mark.parametrize("num_points", [2, 3, 5]) |
|
|
@pytest.mark.parametrize("num_dims", [2, 3]) |
|
|
def test_transform_points(self, batch_size, num_points, num_dims, device, dtype): |
|
|
|
|
|
eye_size = num_dims + 1 |
|
|
points_src = torch.rand(batch_size, num_points, num_dims, device=device, dtype=dtype) |
|
|
|
|
|
dst_homo_src = utils.create_random_homography(batch_size, eye_size).to(device=device, dtype=dtype) |
|
|
dst_homo_src = dst_homo_src.to(device) |
|
|
|
|
|
|
|
|
points_dst = kornia.geometry.linalg.transform_points(dst_homo_src, points_src) |
|
|
|
|
|
|
|
|
src_homo_dst = torch.inverse(dst_homo_src) |
|
|
points_dst_to_src = kornia.geometry.linalg.transform_points(src_homo_dst, points_dst) |
|
|
|
|
|
|
|
|
assert_close(points_src, points_dst_to_src, atol=1e-4, rtol=1e-4) |
|
|
|
|
|
def test_gradcheck(self, device, dtype): |
|
|
|
|
|
batch_size, num_points, num_dims = 2, 3, 2 |
|
|
eye_size = num_dims + 1 |
|
|
points_src = torch.rand(batch_size, num_points, num_dims, device=device, dtype=dtype) |
|
|
dst_homo_src = utils.create_random_homography(batch_size, eye_size).to(device=device, dtype=dtype) |
|
|
|
|
|
points_src = utils.tensor_to_gradcheck_var(points_src) |
|
|
dst_homo_src = utils.tensor_to_gradcheck_var(dst_homo_src) |
|
|
assert gradcheck(kornia.geometry.transform_points, (dst_homo_src, points_src), raise_exception=True) |
|
|
|
|
|
def test_jit(self, device, dtype): |
|
|
points = torch.ones(1, 2, 2, device=device, dtype=dtype) |
|
|
transform = kornia.eye_like(3, points) |
|
|
op = kornia.geometry.transform_points |
|
|
op_script = torch.jit.script(op) |
|
|
actual = op_script(transform, points) |
|
|
expected = op(transform, points) |
|
|
assert_close(actual, expected, atol=1e-4, rtol=1e-4) |
|
|
|
|
|
|
|
|
class TestComposeTransforms: |
|
|
def test_smoke(self, device, dtype): |
|
|
batch_size = 2 |
|
|
trans_01 = identity_matrix(batch_size=batch_size, device=device, dtype=dtype) |
|
|
trans_12 = identity_matrix(batch_size=batch_size, device=device, dtype=dtype) |
|
|
|
|
|
to_check_1 = kornia.geometry.compose_transformations(trans_01, trans_12) |
|
|
to_check_2 = kornia.geometry.compose_transformations(trans_01[0], trans_12[0]) |
|
|
|
|
|
assert to_check_1.shape == (batch_size, 4, 4) |
|
|
assert to_check_2.shape == (4, 4) |
|
|
|
|
|
def test_exception(self, device, dtype): |
|
|
to_check_1 = torch.rand((7, 4, 4, 3), device=device, dtype=dtype) |
|
|
to_check_2 = torch.rand((5, 10, 10), device=device, dtype=dtype) |
|
|
to_check_3 = torch.rand((6, 4, 4), device=device, dtype=dtype) |
|
|
to_check_4 = torch.rand((4, 4), device=device, dtype=dtype) |
|
|
to_check_5 = torch.rand((3, 3), device=device, dtype=dtype) |
|
|
|
|
|
|
|
|
with pytest.raises(ValueError): |
|
|
_ = kornia.geometry.compose_transformations(to_check_5, to_check_5) |
|
|
|
|
|
|
|
|
with pytest.raises(ValueError): |
|
|
_ = kornia.geometry.compose_transformations(to_check_2, to_check_2) |
|
|
|
|
|
|
|
|
|
|
|
with pytest.raises(ValueError): |
|
|
_ = kornia.geometry.compose_transformations(to_check_3, to_check_4) |
|
|
|
|
|
|
|
|
|
|
|
with pytest.raises(ValueError): |
|
|
_ = kornia.geometry.compose_transformations(to_check_1, to_check_4) |
|
|
|
|
|
def test_translation_4x4(self, device, dtype): |
|
|
offset = 10 |
|
|
trans_01 = identity_matrix(batch_size=1, device=device, dtype=dtype)[0] |
|
|
trans_12 = identity_matrix(batch_size=1, device=device, dtype=dtype)[0] |
|
|
trans_12[..., :3, -1] += offset |
|
|
|
|
|
trans_02 = kornia.geometry.linalg.compose_transformations(trans_01, trans_12) |
|
|
assert_close(trans_02, trans_12, atol=1e-4, rtol=1e-4) |
|
|
|
|
|
@pytest.mark.parametrize("batch_size", [1, 2, 5]) |
|
|
def test_translation_Bx4x4(self, batch_size, device, dtype): |
|
|
offset = 10 |
|
|
trans_01 = identity_matrix(batch_size, device=device, dtype=dtype) |
|
|
trans_12 = identity_matrix(batch_size, device=device, dtype=dtype) |
|
|
trans_12[..., :3, -1] += offset |
|
|
|
|
|
trans_02 = kornia.geometry.linalg.compose_transformations(trans_01, trans_12) |
|
|
assert_close(trans_02, trans_12, atol=1e-4, rtol=1e-4) |
|
|
|
|
|
@pytest.mark.parametrize("batch_size", [1, 2, 5]) |
|
|
def test_gradcheck(self, batch_size, device, dtype): |
|
|
trans_01 = identity_matrix(batch_size, device=device, dtype=dtype) |
|
|
trans_12 = identity_matrix(batch_size, device=device, dtype=dtype) |
|
|
|
|
|
trans_01 = utils.tensor_to_gradcheck_var(trans_01) |
|
|
trans_12 = utils.tensor_to_gradcheck_var(trans_12) |
|
|
assert gradcheck(kornia.geometry.linalg.compose_transformations, (trans_01, trans_12), raise_exception=True) |
|
|
|
|
|
|
|
|
class TestInverseTransformation: |
|
|
def test_smoke(self, device, dtype): |
|
|
batch_size = 2 |
|
|
trans_01 = identity_matrix(batch_size=batch_size, device=device, dtype=dtype) |
|
|
|
|
|
to_check_1 = kornia.geometry.inverse_transformation(trans_01) |
|
|
to_check_2 = kornia.geometry.inverse_transformation(trans_01[0]) |
|
|
|
|
|
assert to_check_1.shape == (batch_size, 4, 4) |
|
|
assert to_check_2.shape == (4, 4) |
|
|
|
|
|
def test_exception(self, device, dtype): |
|
|
to_check_1 = torch.rand((7, 4, 4, 3), device=device, dtype=dtype) |
|
|
to_check_2 = torch.rand((5, 10, 10), device=device, dtype=dtype) |
|
|
to_check_3 = torch.rand((3, 3), device=device, dtype=dtype) |
|
|
|
|
|
|
|
|
with pytest.raises(ValueError): |
|
|
_ = kornia.geometry.inverse_transformation(to_check_1) |
|
|
|
|
|
|
|
|
with pytest.raises(ValueError): |
|
|
_ = kornia.geometry.inverse_transformation(to_check_2) |
|
|
|
|
|
|
|
|
with pytest.raises(ValueError): |
|
|
_ = kornia.geometry.inverse_transformation(to_check_3) |
|
|
|
|
|
def test_translation_4x4(self, device, dtype): |
|
|
offset = 10 |
|
|
trans_01 = identity_matrix(batch_size=1, device=device, dtype=dtype)[0] |
|
|
trans_01[..., :3, -1] += offset |
|
|
|
|
|
trans_10 = kornia.geometry.linalg.inverse_transformation(trans_01) |
|
|
trans_01_hat = kornia.geometry.linalg.inverse_transformation(trans_10) |
|
|
assert_close(trans_01, trans_01_hat, atol=1e-4, rtol=1e-4) |
|
|
|
|
|
@pytest.mark.parametrize("batch_size", [1, 2, 5]) |
|
|
def test_translation_Bx4x4(self, batch_size, device, dtype): |
|
|
offset = 10 |
|
|
trans_01 = identity_matrix(batch_size, device=device, dtype=dtype) |
|
|
trans_01[..., :3, -1] += offset |
|
|
|
|
|
trans_10 = kornia.geometry.linalg.inverse_transformation(trans_01) |
|
|
trans_01_hat = kornia.geometry.linalg.inverse_transformation(trans_10) |
|
|
assert_close(trans_01, trans_01_hat, atol=1e-4, rtol=1e-4) |
|
|
|
|
|
@pytest.mark.parametrize("batch_size", [1, 2, 5]) |
|
|
def test_rotation_translation_Bx4x4(self, batch_size, device, dtype): |
|
|
offset = 10 |
|
|
x, y, z = 0, 0, kornia.pi |
|
|
ones = torch.ones(batch_size, device=device, dtype=dtype) |
|
|
rmat_01 = euler_angles_to_rotation_matrix(x * ones, y * ones, z * ones) |
|
|
|
|
|
trans_01 = identity_matrix(batch_size, device=device, dtype=dtype) |
|
|
trans_01[..., :3, -1] += offset |
|
|
trans_01[..., :3, :3] = rmat_01[..., :3, :3] |
|
|
|
|
|
trans_10 = kornia.geometry.linalg.inverse_transformation(trans_01) |
|
|
trans_01_hat = kornia.geometry.linalg.inverse_transformation(trans_10) |
|
|
assert_close(trans_01, trans_01_hat, atol=1e-4, rtol=1e-4) |
|
|
|
|
|
@pytest.mark.parametrize("batch_size", [1, 2, 5]) |
|
|
def test_gradcheck(self, batch_size, device, dtype): |
|
|
trans_01 = identity_matrix(batch_size, device=device, dtype=dtype) |
|
|
trans_01 = utils.tensor_to_gradcheck_var(trans_01) |
|
|
assert gradcheck(kornia.geometry.linalg.inverse_transformation, (trans_01,), raise_exception=True) |
|
|
|
|
|
|
|
|
class TestRelativeTransformation: |
|
|
def test_smoke(self, device, dtype): |
|
|
batch_size = 2 |
|
|
trans_01 = identity_matrix(batch_size=batch_size, device=device, dtype=dtype) |
|
|
trans_02 = identity_matrix(batch_size=batch_size, device=device, dtype=dtype) |
|
|
|
|
|
to_check_1 = kornia.geometry.relative_transformation(trans_01, trans_02) |
|
|
to_check_2 = kornia.geometry.relative_transformation(trans_01[0], trans_02[0]) |
|
|
|
|
|
assert to_check_1.shape == (batch_size, 4, 4) |
|
|
assert to_check_2.shape == (4, 4) |
|
|
|
|
|
def test_exception(self, device, dtype): |
|
|
to_check_1 = torch.rand((7, 4, 4, 3), device=device, dtype=dtype) |
|
|
to_check_2 = torch.rand((5, 10, 10), device=device, dtype=dtype) |
|
|
to_check_3 = torch.rand((6, 4, 4), device=device, dtype=dtype) |
|
|
to_check_4 = torch.rand((4, 4), device=device, dtype=dtype) |
|
|
to_check_5 = torch.rand((3, 3), device=device, dtype=dtype) |
|
|
|
|
|
|
|
|
with pytest.raises(ValueError): |
|
|
_ = kornia.geometry.relative_transformation(to_check_5, to_check_5) |
|
|
|
|
|
|
|
|
with pytest.raises(ValueError): |
|
|
_ = kornia.geometry.relative_transformation(to_check_2, to_check_2) |
|
|
|
|
|
|
|
|
|
|
|
with pytest.raises(ValueError): |
|
|
_ = kornia.geometry.relative_transformation(to_check_3, to_check_4) |
|
|
|
|
|
|
|
|
|
|
|
with pytest.raises(ValueError): |
|
|
_ = kornia.geometry.relative_transformation(to_check_1, to_check_4) |
|
|
|
|
|
def test_translation_4x4(self, device, dtype): |
|
|
offset = 10.0 |
|
|
trans_01 = identity_matrix(batch_size=1, device=device, dtype=dtype)[0] |
|
|
trans_02 = identity_matrix(batch_size=1, device=device, dtype=dtype)[0] |
|
|
trans_02[..., :3, -1] += offset |
|
|
|
|
|
trans_12 = kornia.geometry.linalg.relative_transformation(trans_01, trans_02) |
|
|
trans_02_hat = kornia.geometry.linalg.compose_transformations(trans_01, trans_12) |
|
|
assert_close(trans_02_hat, trans_02, atol=1e-4, rtol=1e-4) |
|
|
|
|
|
@pytest.mark.parametrize("batch_size", [1, 2, 5]) |
|
|
def test_rotation_translation_Bx4x4(self, batch_size, device, dtype): |
|
|
offset = 10.0 |
|
|
x, y, z = 0.0, 0.0, kornia.pi |
|
|
ones = torch.ones(batch_size, device=device, dtype=dtype) |
|
|
rmat_02 = euler_angles_to_rotation_matrix(x * ones, y * ones, z * ones) |
|
|
|
|
|
trans_01 = identity_matrix(batch_size, device=device, dtype=dtype) |
|
|
trans_02 = identity_matrix(batch_size, device=device, dtype=dtype) |
|
|
trans_02[..., :3, -1] += offset |
|
|
trans_02[..., :3, :3] = rmat_02[..., :3, :3] |
|
|
|
|
|
trans_12 = kornia.geometry.linalg.relative_transformation(trans_01, trans_02) |
|
|
trans_02_hat = kornia.geometry.linalg.compose_transformations(trans_01, trans_12) |
|
|
assert_close(trans_02_hat, trans_02, atol=1e-4, rtol=1e-4) |
|
|
|
|
|
@pytest.mark.parametrize("batch_size", [1, 2, 5]) |
|
|
def test_gradcheck(self, batch_size, device, dtype): |
|
|
trans_01 = identity_matrix(batch_size, device=device, dtype=dtype) |
|
|
trans_02 = identity_matrix(batch_size, device=device, dtype=dtype) |
|
|
|
|
|
trans_01 = utils.tensor_to_gradcheck_var(trans_01) |
|
|
trans_02 = utils.tensor_to_gradcheck_var(trans_02) |
|
|
assert gradcheck(kornia.geometry.linalg.relative_transformation, (trans_01, trans_02), raise_exception=True) |
|
|
|