| | from typing import Dict |
| |
|
| | import pytest |
| | import test_common as utils |
| | import torch |
| | from torch.autograd import gradcheck |
| |
|
| | import kornia.geometry.epipolar as epi |
| | from kornia.testing import assert_close |
| |
|
| |
|
| | class TestNormalizePoints: |
| | def test_smoke(self, device, dtype): |
| | points = torch.rand(1, 1, 2, device=device, dtype=dtype) |
| | output = epi.normalize_points(points) |
| | assert len(output) == 2 |
| | assert output[0].shape == (1, 1, 2) |
| | assert output[1].shape == (1, 3, 3) |
| |
|
| | @pytest.mark.parametrize("batch_size, num_points", [(1, 2), (2, 3), (3, 2)]) |
| | def test_shape(self, batch_size, num_points, device, dtype): |
| | B, N = batch_size, num_points |
| | points = torch.rand(B, N, 2, device=device, dtype=dtype) |
| | output = epi.normalize_points(points) |
| | assert output[0].shape == (B, N, 2) |
| | assert output[1].shape == (B, 3, 3) |
| |
|
| | def test_mean_std(self, device, dtype): |
| | points = torch.tensor([[[0.0, 0.0], [0.0, 2.0], [1.0, 1.0], [1.0, 3.0]]], device=device, dtype=dtype) |
| |
|
| | points_norm, _ = epi.normalize_points(points) |
| | points_std, points_mean = torch.std_mean(points_norm, dim=1) |
| |
|
| | assert_close(points_mean, torch.zeros_like(points_mean)) |
| | assert (points_std < 2.0).all() |
| |
|
| | def test_gradcheck(self, device): |
| | points = torch.rand(2, 3, 2, device=device, requires_grad=True, dtype=torch.float64) |
| | assert gradcheck(epi.normalize_points, (points,), raise_exception=True) |
| |
|
| |
|
| | class TestNormalizeTransformation: |
| | def test_smoke(self, device, dtype): |
| | trans = torch.rand(2, 2, device=device, dtype=dtype) |
| | trans_norm = epi.normalize_transformation(trans) |
| | assert trans_norm.shape == (2, 2) |
| |
|
| | @pytest.mark.parametrize("batch_size, rows, cols", [(1, 2, 2), (2, 3, 3), (3, 4, 4), (2, 1, 2)]) |
| | def test_shape(self, batch_size, rows, cols, device, dtype): |
| | B, N, M = batch_size, rows, cols |
| | trans = torch.rand(B, N, M, device=device, dtype=dtype) |
| | trans_norm = epi.normalize_transformation(trans) |
| | assert trans_norm.shape == (B, N, M) |
| |
|
| | def test_check_last_val(self, device, dtype): |
| | trans = torch.tensor([[[0.0, 0.0, 1.0], [0.0, 2.0, 0.0], [0.5, 0.0, 0.5]]], device=device, dtype=dtype) |
| |
|
| | trans_expected = torch.tensor([[[0.0, 0.0, 2.0], [0.0, 4.0, 0.0], [1.0, 0.0, 1.0]]], device=device, dtype=dtype) |
| |
|
| | trans_norm = epi.normalize_transformation(trans) |
| | assert_close(trans_norm, trans_expected, atol=1e-4, rtol=1e-4) |
| |
|
| | def test_check_corner_case(self, device, dtype): |
| | trans = torch.tensor([[[0.0, 0.0, 1.0], [0.0, 2.0, 0.0], [0.5, 0.0, 0.0]]], device=device, dtype=dtype) |
| |
|
| | trans_expected = trans.clone() |
| |
|
| | trans_norm = epi.normalize_transformation(trans) |
| | assert_close(trans_norm, trans_expected, atol=1e-4, rtol=1e-4) |
| |
|
| | def test_gradcheck(self, device): |
| | trans = torch.rand(2, 3, 3, device=device, requires_grad=True, dtype=torch.float64) |
| | assert gradcheck(epi.normalize_transformation, (trans,), raise_exception=True) |
| |
|
| |
|
| | class TestFindFundamental: |
| | def test_smoke(self, device, dtype): |
| | points1 = torch.rand(1, 1, 2, device=device, dtype=dtype) |
| | points2 = torch.rand(1, 1, 2, device=device, dtype=dtype) |
| | weights = torch.ones(1, 1, device=device, dtype=dtype) |
| | F_mat = epi.find_fundamental(points1, points2, weights) |
| | assert F_mat.shape == (1, 3, 3) |
| |
|
| | @pytest.mark.parametrize("batch_size, num_points", [(1, 2), (2, 3), (3, 2)]) |
| | def test_shape(self, batch_size, num_points, device, dtype): |
| | B, N = batch_size, num_points |
| | points1 = torch.rand(B, N, 2, device=device, dtype=dtype) |
| | points2 = torch.rand(B, N, 2, device=device, dtype=dtype) |
| | weights = torch.ones(B, N, device=device, dtype=dtype) |
| | F_mat = epi.find_fundamental(points1, points2, weights) |
| | assert F_mat.shape == (B, 3, 3) |
| |
|
| | def test_opencv(self, device, dtype): |
| | points1 = torch.tensor( |
| | [ |
| | [ |
| | [0.8569, 0.5982], |
| | [0.0059, 0.9649], |
| | [0.1968, 0.8846], |
| | [0.6084, 0.3467], |
| | [0.9633, 0.5274], |
| | [0.8941, 0.8939], |
| | [0.0863, 0.5133], |
| | [0.2645, 0.8882], |
| | [0.2411, 0.3045], |
| | [0.8199, 0.4107], |
| | ] |
| | ], |
| | device=device, |
| | dtype=dtype, |
| | ) |
| |
|
| | points2 = torch.tensor( |
| | [ |
| | [ |
| | [0.0928, 0.3013], |
| | [0.0989, 0.9649], |
| | [0.0341, 0.4827], |
| | [0.8294, 0.4469], |
| | [0.2230, 0.2998], |
| | [0.1722, 0.8182], |
| | [0.5264, 0.8869], |
| | [0.8908, 0.1233], |
| | [0.2338, 0.7663], |
| | [0.4466, 0.5696], |
| | ] |
| | ], |
| | device=device, |
| | dtype=dtype, |
| | ) |
| |
|
| | weights = torch.ones(1, 10, device=device, dtype=dtype) |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | Fm_expected = torch.tensor( |
| | [ |
| | [ |
| | [-0.47408533, 0.22033807, -0.00346677], |
| | [0.54935973, 1.31080955, -1.25028275], |
| | [-0.36690215, -1.08143769, 1.0], |
| | ] |
| | ], |
| | device=device, |
| | dtype=dtype, |
| | ) |
| |
|
| | F_mat = epi.find_fundamental(points1, points2, weights) |
| | assert_close(F_mat, Fm_expected, rtol=1e-4, atol=1e-4) |
| |
|
| | @pytest.mark.xfail(reason="TODO: fix #685") |
| | def test_synthetic_sampson(self, device, dtype): |
| |
|
| | scene: Dict[str, torch.Tensor] = utils.generate_two_view_random_scene(device, dtype) |
| |
|
| | x1 = scene['x1'] |
| | x2 = scene['x2'] |
| |
|
| | weights = torch.ones_like(x1)[..., 0] |
| | F_est = epi.find_fundamental(x1, x2, weights) |
| |
|
| | error = epi.sampson_epipolar_distance(x1, x2, F_est) |
| | assert_close(error, torch.tensor(0.0, device=device, dtype=dtype), atol=1e-4, rtol=1e-4) |
| |
|
| | def test_gradcheck(self, device): |
| | points1 = torch.rand(1, 10, 2, device=device, dtype=torch.float64, requires_grad=True) |
| | points2 = torch.rand(1, 10, 2, device=device, dtype=torch.float64) |
| | weights = torch.ones(1, 10, device=device, dtype=torch.float64) |
| | assert gradcheck(epi.find_fundamental, (points1, points2, weights), raise_exception=True) |
| |
|
| |
|
| | class TestComputeCorrespondEpilimes: |
| | def test_smoke(self, device, dtype): |
| | point = torch.rand(1, 1, 2, device=device, dtype=dtype) |
| | F_mat = torch.rand(1, 3, 3, device=device, dtype=dtype) |
| | lines = epi.compute_correspond_epilines(point, F_mat) |
| | assert lines.shape == (1, 1, 3) |
| |
|
| | @pytest.mark.parametrize("batch_size, num_points", [(1, 2), (2, 3), (3, 2)]) |
| | def test_shape(self, batch_size, num_points, device, dtype): |
| | B, N = batch_size, num_points |
| | point = torch.rand(B, N, 2, device=device, dtype=dtype) |
| | F_mat = torch.rand(B, 3, 3, device=device, dtype=dtype) |
| | lines = epi.compute_correspond_epilines(point, F_mat) |
| | assert lines.shape == (B, N, 3) |
| |
|
| | def test_opencv(self, device, dtype): |
| | point = torch.rand(1, 2, 2, device=device, dtype=dtype) |
| | F_mat = torch.rand(1, 3, 3, device=device, dtype=dtype) |
| |
|
| | point = torch.tensor([[[0.9794, 0.7994], [0.8163, 0.8500]]], device=device, dtype=dtype) |
| |
|
| | F_mat = torch.tensor( |
| | [[[0.1185, 0.4438, 0.9869], [0.5670, 0.9447, 0.4100], [0.1546, 0.2554, 0.4485]]], device=device, dtype=dtype |
| | ) |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | lines_expected = torch.tensor( |
| | [[[0.64643687, 0.7629675, 0.35658622], [0.65710586, 0.7537983, 0.35616538]]], device=device, dtype=dtype |
| | ) |
| |
|
| | lines_est = epi.compute_correspond_epilines(point, F_mat) |
| | assert_close(lines_est, lines_expected, rtol=1e-4, atol=1e-4) |
| |
|
| | def test_gradcheck(self, device): |
| | point = torch.rand(1, 4, 2, device=device, dtype=torch.float64, requires_grad=True) |
| | F_mat = torch.rand(1, 3, 3, device=device, dtype=torch.float64) |
| | assert gradcheck(epi.compute_correspond_epilines, (point, F_mat), raise_exception=True) |
| |
|
| |
|
| | class TestFundamentlFromEssential: |
| | def test_smoke(self, device, dtype): |
| | E_mat = torch.rand(1, 3, 3, device=device, dtype=dtype) |
| | K1 = torch.rand(1, 3, 3, device=device, dtype=dtype) |
| | K2 = torch.rand(1, 3, 3, device=device, dtype=dtype) |
| | F_mat = epi.fundamental_from_essential(E_mat, K1, K2) |
| | assert F_mat.shape == (1, 3, 3) |
| |
|
| | @pytest.mark.parametrize("batch_size", [1, 2, 4, 7]) |
| | def test_shape(self, batch_size, device, dtype): |
| | B: int = batch_size |
| | E_mat = torch.rand(B, 3, 3, device=device, dtype=dtype) |
| | K1 = torch.rand(B, 3, 3, device=device, dtype=dtype) |
| | K2 = torch.rand(1, 3, 3, device=device, dtype=dtype) |
| | F_mat = epi.fundamental_from_essential(E_mat, K1, K2) |
| | assert F_mat.shape == (B, 3, 3) |
| |
|
| | def test_shape_large(self, device, dtype): |
| | E_mat = torch.rand(1, 2, 3, 3, device=device, dtype=dtype) |
| | K1 = torch.rand(1, 2, 3, 3, device=device, dtype=dtype) |
| | K2 = torch.rand(1, 1, 3, 3, device=device, dtype=dtype) |
| | F_mat = epi.fundamental_from_essential(E_mat, K1, K2) |
| | assert F_mat.shape == (1, 2, 3, 3) |
| |
|
| | def test_from_to_essential(self, device, dtype): |
| | scene = utils.generate_two_view_random_scene(device, dtype) |
| |
|
| | F_mat = scene['F'] |
| | E_mat = epi.essential_from_fundamental(F_mat, scene['K1'], scene['K2']) |
| | F_hat = epi.fundamental_from_essential(E_mat, scene['K1'], scene['K2']) |
| |
|
| | F_mat_norm = epi.normalize_transformation(F_mat) |
| | F_hat_norm = epi.normalize_transformation(F_hat) |
| | assert_close(F_mat_norm, F_hat_norm, atol=1e-4, rtol=1e-4) |
| |
|
| | def test_gradcheck(self, device): |
| | E_mat = torch.rand(1, 3, 3, device=device, dtype=torch.float64, requires_grad=True) |
| | K1 = torch.rand(1, 3, 3, device=device, dtype=torch.float64) |
| | K2 = torch.rand(1, 3, 3, device=device, dtype=torch.float64) |
| | assert gradcheck(epi.fundamental_from_essential, (E_mat, K1, K2), raise_exception=True) |
| |
|
| |
|
| | class TestFundamentalFromProjections: |
| | def test_smoke(self, device, dtype): |
| | P1 = torch.rand(1, 3, 4, device=device, dtype=dtype) |
| | P2 = torch.rand(1, 3, 4, device=device, dtype=dtype) |
| | F_mat = epi.fundamental_from_projections(P1, P2) |
| | assert F_mat.shape == (1, 3, 3) |
| |
|
| | @pytest.mark.parametrize("batch_size", [1, 2, 4, 7]) |
| | def test_shape(self, batch_size, device, dtype): |
| | B: int = batch_size |
| | P1 = torch.rand(B, 3, 4, device=device, dtype=dtype) |
| | P2 = torch.rand(B, 3, 4, device=device, dtype=dtype) |
| | F_mat = epi.fundamental_from_projections(P1, P2) |
| | assert F_mat.shape == (B, 3, 3) |
| |
|
| | def test_shape_large(self, device, dtype): |
| | P1 = torch.rand(1, 2, 3, 4, device=device, dtype=dtype) |
| | P2 = torch.rand(1, 2, 3, 4, device=device, dtype=dtype) |
| | F_mat = epi.fundamental_from_projections(P1, P2) |
| | assert F_mat.shape == (1, 2, 3, 3) |
| |
|
| | def test_from_to_projections(self, device, dtype): |
| | P1 = torch.tensor( |
| | [[[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [1.0, 0.0, 1.0, 0.0]]], device=device, dtype=dtype |
| | ) |
| |
|
| | P2 = torch.tensor( |
| | [[[1.0, 1.0, 1.0, 3.0], [0.0, 2.0, 0.0, 3.0], [0.0, 1.0, 1.0, 0.0]]], device=device, dtype=dtype |
| | ) |
| |
|
| | F_mat = epi.fundamental_from_projections(P1, P2) |
| | P_mat = epi.projections_from_fundamental(F_mat) |
| | F_hat = epi.fundamental_from_projections(P_mat[..., 0], P_mat[..., 1]) |
| |
|
| | F_mat_norm = epi.normalize_transformation(F_mat) |
| | F_hat_norm = epi.normalize_transformation(F_hat) |
| | assert_close(F_mat_norm, F_hat_norm, atol=1e-4, rtol=1e-4) |
| |
|
| | def test_gradcheck(self, device): |
| | P1 = torch.rand(1, 3, 4, device=device, dtype=torch.float64, requires_grad=True) |
| | P2 = torch.rand(1, 3, 4, device=device, dtype=torch.float64) |
| | assert gradcheck(epi.fundamental_from_projections, (P1, P2), raise_exception=True) |
| |
|
| | def test_batch_support_check(self, device, dtype): |
| | P1_batch = torch.tensor( |
| | [ |
| | [ |
| | [9.4692e02, -9.6658e02, 6.0862e02, -2.3076e05], |
| | [-2.1829e02, 5.4163e02, 1.3445e03, -6.4387e05], |
| | [-6.0675e-01, -6.9807e-01, 3.8021e-01, 3.8896e02], |
| | ], |
| | [ |
| | [9.4692e02, -9.6658e02, 6.0862e02, -2.3076e05], |
| | [-2.1829e02, 5.4163e02, 1.3445e03, -6.4387e05], |
| | [-6.0675e-01, -6.9807e-01, 3.8021e-01, 3.8896e02], |
| | ], |
| | ], |
| | device=device, |
| | dtype=dtype, |
| | ) |
| | P1 = torch.tensor( |
| | [ |
| | [ |
| | [9.4692e02, -9.6658e02, 6.0862e02, -2.3076e05], |
| | [-2.1829e02, 5.4163e02, 1.3445e03, -6.4387e05], |
| | [-6.0675e-01, -6.9807e-01, 3.8021e-01, 3.8896e02], |
| | ] |
| | ], |
| | device=device, |
| | dtype=dtype, |
| | ) |
| | P2_batch = torch.tensor( |
| | [ |
| | [ |
| | [1.1518e03, -7.5822e02, 5.4764e02, -1.9764e05], |
| | [-2.1548e02, 5.3102e02, 1.3492e03, -6.4731e05], |
| | [-4.3727e-01, -7.8632e-01, 4.3646e-01, 3.4515e02], |
| | ], |
| | [ |
| | [9.9595e02, -8.6464e02, 6.7959e02, -2.7517e05], |
| | [-8.1716e01, 7.7826e02, 1.2395e03, -5.8137e05], |
| | [-5.7090e-01, -6.0416e-01, 5.5594e-01, 2.8111e02], |
| | ], |
| | ], |
| | device=device, |
| | dtype=dtype, |
| | ) |
| | P2 = torch.tensor( |
| | [ |
| | [ |
| | [1.1518e03, -7.5822e02, 5.4764e02, -1.9764e05], |
| | [-2.1548e02, 5.3102e02, 1.3492e03, -6.4731e05], |
| | [-4.3727e-01, -7.8632e-01, 4.3646e-01, 3.4515e02], |
| | ] |
| | ], |
| | device=device, |
| | dtype=dtype, |
| | ) |
| |
|
| | F_batch = epi.fundamental_from_projections(P1_batch, P2_batch) |
| | F = epi.fundamental_from_projections(P1, P2) |
| | assert (F_batch[0] == F[0]).all() |
| |
|