compvis / test /geometry /epipolar /test_fundamental.py
Dexter's picture
Upload folder using huggingface_hub
36c95ba verified
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)
# generated with OpenCV using above points
# import cv2
# Fm_expected, _ = cv2.findFundamentalMat(
# points1.detach().numpy().reshape(-1, 1, 2),
# points2.detach().numpy().reshape(-1, 1, 2), cv2.FM_8POINT)
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
)
# generated with OpenCV using above points
# import cv2
# lines_expected = cv2.computeCorrespondEpilines(
# point.detach().numpy().reshape(-1, 1, 2), 0,
# F_mat.detach().numpy()[0]).transpose(1, 0, 2)
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) # check broadcasting
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) # check broadcasting
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()