Dexter's picture
Upload folder using huggingface_hub
36c95ba verified
import pytest
import torch
from torch.autograd import gradcheck
import kornia
from kornia.geometry.calibration.pnp import _mean_isotropic_scale_normalize
from kornia.testing import assert_close, tensor_to_gradcheck_var
class TestSolvePnpDlt:
@staticmethod
def _get_samples(shape, low, high, device, dtype):
"""Return a tensor having the given shape and whose values are in the range [low, high)"""
return ((high - low) * torch.rand(shape, device=device, dtype=dtype)) + low
@staticmethod
def _project_to_image(world_points, world_to_cam_4x4, repeated_intrinsics):
r"""Projects points in the world coordinate system to the image coordinate system.
Since cam_points will have shape (B, N, 3), repeated_intrinsics should have
shape (B, N, 3, 3) so that kornia.geometry.project_points can be used.
"""
cam_points = kornia.geometry.transform_points(world_to_cam_4x4, world_points)
img_points = kornia.geometry.project_points(cam_points, repeated_intrinsics)
return img_points
@staticmethod
def _get_world_points_and_img_points(cam_points, world_to_cam_4x4, repeated_intrinsics):
r"""Calculates world_points and img_points.
Since cam_points will have shape (B, N, 3), repeated_intrinsics should have
shape (B, N, 3, 3) so that kornia.geometry.project_points can be used.
"""
cam_to_world_4x4 = kornia.geometry.inverse_transformation(world_to_cam_4x4)
world_points = kornia.geometry.transform_points(cam_to_world_4x4, cam_points)
img_points = kornia.geometry.project_points(cam_points, repeated_intrinsics)
return world_points, img_points
def _get_test_data(self, num_points, device, dtype):
"""Creates some test data.
Batch size is fixed to 2 for all tests.
"""
batch_size = 2
torch.manual_seed(84)
tau = 2 * 3.141592653589793
angle_axis_1 = self._get_samples(shape=(1, 3), low=-tau, high=tau, dtype=dtype, device=device)
angle_axis_2 = self._get_samples(shape=(1, 3), low=-tau, high=tau, dtype=dtype, device=device)
rotation_1 = kornia.geometry.angle_axis_to_rotation_matrix(angle_axis_1)
rotation_2 = kornia.geometry.angle_axis_to_rotation_matrix(angle_axis_2)
translation_1 = self._get_samples(shape=(3,), low=-100, high=100, dtype=dtype, device=device)
translation_2 = self._get_samples(shape=(3,), low=-100, high=100, dtype=dtype, device=device)
temp = torch.eye(4, dtype=dtype, device=device)
world_to_cam_mats = temp.unsqueeze(0).repeat(batch_size, 1, 1)
world_to_cam_mats[0, :3, :3] = torch.squeeze(rotation_1)
world_to_cam_mats[0, :3, 3] = translation_1
world_to_cam_mats[1, :3, :3] = torch.squeeze(rotation_2)
world_to_cam_mats[1, :3, 3] = translation_2
intrinsic_1 = torch.tensor(
[[500.0, 0.0, 250.0], [0.0, 500.0, 250.0], [0.0, 0.0, 1.0]], dtype=dtype, device=device
)
intrinsic_2 = torch.tensor(
[[1000.0, 0.0, 550.0], [0.0, 750.0, 200.0], [0.0, 0.0, 1.0]], dtype=dtype, device=device
)
intrinsics = torch.stack([intrinsic_1, intrinsic_2], dim=0)
cam_points_xy = self._get_samples(
shape=(batch_size, num_points, 2), low=-100, high=100, dtype=dtype, device=device
)
cam_points_z = self._get_samples(
shape=(batch_size, num_points, 1), low=0.5, high=100, dtype=dtype, device=device
)
cam_points = torch.cat([cam_points_xy, cam_points_z], dim=-1)
repeated_intrinsics = intrinsics.unsqueeze(1).repeat(1, num_points, 1, 1)
world_points, img_points = self._get_world_points_and_img_points(
cam_points, world_to_cam_mats, repeated_intrinsics
)
world_to_cam_3x4 = world_to_cam_mats[:, :3, :]
return intrinsics, world_to_cam_3x4, world_points, img_points
@pytest.mark.parametrize("num_points", (6, 20,))
def test_smoke(self, num_points, device, dtype):
intrinsics, _, world_points, img_points = self._get_test_data(num_points, device, dtype)
batch_size = world_points.shape[0]
pred_world_to_cam = kornia.geometry.solve_pnp_dlt(world_points, img_points, intrinsics)
assert pred_world_to_cam.shape == (batch_size, 3, 4)
@pytest.mark.parametrize("num_points", (6,))
def test_gradcheck(self, num_points, device, dtype):
intrinsics, _, world_points, img_points = self._get_test_data(num_points, device, dtype)
world_points = tensor_to_gradcheck_var(world_points)
img_points = tensor_to_gradcheck_var(img_points)
intrinsics = tensor_to_gradcheck_var(intrinsics)
assert gradcheck(kornia.geometry.solve_pnp_dlt, (world_points, img_points, intrinsics), raise_exception=True)
@pytest.mark.parametrize("num_points", (6, 20,))
def test_pred_world_to_cam(self, num_points, device, dtype):
intrinsics, gt_world_to_cam, world_points, img_points = self._get_test_data(num_points, device, dtype)
pred_world_to_cam = kornia.geometry.solve_pnp_dlt(world_points, img_points, intrinsics)
assert_close(pred_world_to_cam, gt_world_to_cam, atol=1e-4, rtol=1e-4)
@pytest.mark.parametrize("num_points", (6, 20,))
def test_project(self, num_points, device, dtype):
intrinsics, _, world_points, img_points = self._get_test_data(num_points, device, dtype)
pred_world_to_cam = kornia.geometry.solve_pnp_dlt(world_points, img_points, intrinsics)
pred_world_to_cam_4x4 = kornia.eye_like(4, pred_world_to_cam)
pred_world_to_cam_4x4[:, :3, :] = pred_world_to_cam
repeated_intrinsics = intrinsics.unsqueeze(1).repeat(1, num_points, 1, 1)
pred_img_points = self._project_to_image(world_points, pred_world_to_cam_4x4, repeated_intrinsics)
assert_close(pred_img_points, img_points, atol=1e-3, rtol=1e-3)
class TestNormalization:
@pytest.mark.parametrize("dimension", (2, 3, 5))
def test_smoke(self, dimension, device, dtype):
batch_size = 10
num_points = 100
points = torch.rand((batch_size, num_points, dimension), device=device, dtype=dtype)
points_norm, transform = _mean_isotropic_scale_normalize(points)
assert points_norm.shape == (batch_size, num_points, dimension)
assert transform.shape == (batch_size, dimension + 1, dimension + 1)
@pytest.mark.parametrize("dimension", (2, 3, 5))
def test_gradcheck(self, dimension, device, dtype):
batch_size = 3
num_points = 5
points = torch.rand((batch_size, num_points, dimension), device=device, dtype=dtype)
points = tensor_to_gradcheck_var(points)
assert gradcheck(_mean_isotropic_scale_normalize, (points,), raise_exception=True)