Exemplo n.º 1
0
    def test_bad_so3_input_value_err(self):
        """
        Tests whether `so3_exp_map` and `so3_log_map` correctly return
        a ValueError if called with an argument of incorrect shape or, in case
        of `so3_exp_map`, unexpected trace.
        """
        device = torch.device("cuda:0")
        log_rot = torch.randn(size=[5, 4], device=device)
        with self.assertRaises(ValueError) as err:
            so3_exp_map(log_rot)
        self.assertTrue(
            "Input tensor shape has to be Nx3." in str(err.exception))

        rot = torch.randn(size=[5, 3, 5], device=device)
        with self.assertRaises(ValueError) as err:
            so3_log_map(rot)
        self.assertTrue(
            "Input has to be a batch of 3x3 Tensors." in str(err.exception))

        # trace of rot definitely bigger than 3 or smaller than -1
        rot = torch.cat((
            torch.rand(size=[5, 3, 3], device=device) + 4.0,
            torch.rand(size=[5, 3, 3], device=device) - 3.0,
        ))
        with self.assertRaises(ValueError) as err:
            so3_log_map(rot)
        self.assertTrue(
            "A matrix has trace outside valid range [-1-eps,3+eps]." in str(
                err.exception))
Exemplo n.º 2
0
    def init_equiv_cameras_ndc_screen(cam_type: CamerasBase, batch_size: int):
        T = torch.randn(batch_size, 3) * 0.03
        T[:, 2] = 4
        R = so3_exp_map(torch.randn(batch_size, 3) * 3.0)
        screen_cam_params = {"R": R, "T": T}
        ndc_cam_params = {"R": R, "T": T}
        if cam_type in (OrthographicCameras, PerspectiveCameras):
            fcl = torch.rand((batch_size, 2)) * 3.0 + 0.1
            prc = torch.randn((batch_size, 2)) * 0.2
            # (height, width)
            image_size = torch.randint(low=2, high=64, size=(batch_size, 2))
            # scale
            scale = (image_size.min(dim=1, keepdim=True).values - 1.0) / 2.0

            ndc_cam_params["focal_length"] = fcl
            ndc_cam_params["principal_point"] = prc
            ndc_cam_params["image_size"] = image_size

            screen_cam_params["image_size"] = image_size
            screen_cam_params["focal_length"] = fcl * scale
            screen_cam_params["principal_point"] = (image_size[:, [1, 0]] -
                                                    1.0) / 2.0 - prc * scale
            screen_cam_params["in_ndc"] = False
        else:
            raise ValueError(str(cam_type))
        return cam_type(**ndc_cam_params), cam_type(**screen_cam_params)
Exemplo n.º 3
0
 def test_determinant(self):
     """
     Tests whether the determinants of 3x3 rotation matrices produced
     by `so3_exp_map` are (almost) equal to 1.
     """
     log_rot = TestSO3.init_log_rot(batch_size=30)
     Rs = so3_exp_map(log_rot)
     dets = torch.det(Rs)
     self.assertClose(dets, torch.ones_like(dets), atol=1e-4)
Exemplo n.º 4
0
 def test_so3_log_to_exp_to_log_to_exp(self, batch_size: int = 100):
     """
     Check that
     `so3_exp_map(so3_log_map(so3_exp_map(log_rot)))
     == so3_exp_map(log_rot)`
     for a randomly generated batch of rotation matrix logarithms `log_rot`.
     Unlike `test_so3_log_to_exp_to_log`, this test checks the
     correctness of converting a `log_rot` which contains values > math.pi.
     """
     log_rot = 2.0 * TestSO3.init_log_rot(batch_size=batch_size)
     # check also the singular cases where rot. angle = {0, 2pi}
     log_rot[:2] = 0
     log_rot[1, 0] = 2.0 * math.pi - 1e-6
     rot = so3_exp_map(log_rot, eps=1e-4)
     rot_ = so3_exp_map(so3_log_map(rot, eps=1e-4, cos_bound=1e-6),
                        eps=1e-6)
     self.assertClose(rot, rot_, atol=0.01)
     angles = so3_relative_angle(rot, rot_, cos_bound=1e-6)
     self.assertClose(angles, torch.zeros_like(angles), atol=0.01)
Exemplo n.º 5
0
 def test_so3_log_to_exp_to_log(self, batch_size: int = 100):
     """
     Check that `so3_log_map(so3_exp_map(log_rot))==log_rot` for
     a randomly generated batch of rotation matrix logarithms `log_rot`.
     """
     log_rot = TestSO3.init_log_rot(batch_size=batch_size)
     # check also the singular cases where rot. angle = 0
     log_rot[:1] = 0
     log_rot_ = so3_log_map(so3_exp_map(log_rot))
     self.assertClose(log_rot, log_rot_, atol=1e-4)
Exemplo n.º 6
0
 def test_inverse(self, batch_size=5):
     device = torch.device("cuda:0")
     log_rot = torch.randn((batch_size, 3), dtype=torch.float32, device=device)
     R = so3_exp_map(log_rot)
     t = Rotate(R)
     im = t.inverse()._matrix
     im_2 = t._matrix.inverse()
     im_comp = t.get_matrix().inverse()
     self.assertTrue(torch.allclose(im, im_comp, atol=1e-4))
     self.assertTrue(torch.allclose(im, im_2, atol=1e-4))
Exemplo n.º 7
0
    def test_inverse(self, batch_size=5):
        device = torch.device("cuda:0")

        # generate a random chain of transforms
        for _ in range(10):  # 10 different tries

            # list of transform matrices
            ts = []

            for i in range(10):
                choice = float(torch.rand(1))
                if choice <= 1.0 / 3.0:
                    t_ = Translate(
                        torch.randn(
                            (batch_size, 3), dtype=torch.float32, device=device
                        ),
                        device=device,
                    )
                elif choice <= 2.0 / 3.0:
                    t_ = Rotate(
                        so3_exp_map(
                            torch.randn(
                                (batch_size, 3), dtype=torch.float32, device=device
                            )
                        ),
                        device=device,
                    )
                else:
                    rand_t = torch.randn(
                        (batch_size, 3), dtype=torch.float32, device=device
                    )
                    rand_t = rand_t.sign() * torch.clamp(rand_t.abs(), 0.2)
                    t_ = Scale(rand_t, device=device)
                ts.append(t_._matrix.clone())

                if i == 0:
                    t = t_
                else:
                    t = t.compose(t_)

            # generate the inverse transformation in several possible ways
            m1 = t.inverse(invert_composed=True).get_matrix()
            m2 = t.inverse(invert_composed=True)._matrix
            m3 = t.inverse(invert_composed=False).get_matrix()
            m4 = t.get_matrix().inverse()

            # compute the inverse explicitly ...
            m5 = torch.eye(4, dtype=torch.float32, device=device)
            m5 = m5[None].repeat(batch_size, 1, 1)
            for t_ in ts:
                m5 = torch.bmm(torch.inverse(t_), m5)

            # assert all same
            for m in (m1, m2, m3, m4):
                self.assertTrue(torch.allclose(m, m5, atol=1e-3))
Exemplo n.º 8
0
def init_uniform_y_rotations(batch_size: int, device: torch.device):
    """
    Generate a batch of `batch_size` 3x3 rotation matrices around y-axis
    whose angles are uniformly distributed between 0 and 2 pi.
    """
    axis = torch.tensor([0.0, 1.0, 0.0], device=device, dtype=torch.float32)
    angles = torch.linspace(0, 2.0 * np.pi, batch_size + 1, device=device)
    angles = angles[:batch_size]
    log_rots = axis[None, :] * angles[:, None]
    R = so3_exp_map(log_rots)
    return R
Exemplo n.º 9
0
 def test_so3_exp_to_log_to_exp(self, batch_size: int = 100):
     """
     Check that `so3_exp_map(so3_log_map(R))==R` for
     a batch of randomly generated rotation matrices `R`.
     """
     rot = TestSO3.init_rot(batch_size=batch_size)
     non_singular = (so3_rotation_angle(rot) - math.pi).abs() > 1e-2
     rot = rot[non_singular]
     rot_ = so3_exp_map(so3_log_map(rot, eps=1e-8, cos_bound=1e-8),
                        eps=1e-8)
     self.assertClose(rot_, rot, atol=0.1)
     angles = so3_relative_angle(rot, rot_, cos_bound=1e-4)
     self.assertClose(angles, torch.zeros_like(angles), atol=0.1)
Exemplo n.º 10
0
 def test_rotate(self):
     R = so3_exp_map(torch.randn((1, 3)))
     t = Transform3d().rotate(R)
     points = torch.tensor([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0],
                            [0.5, 0.5, 0.0]]).view(1, 3, 3)
     normals = torch.tensor([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0],
                             [1.0, 1.0, 0.0]]).view(1, 3, 3)
     points_out = t.transform_points(points)
     normals_out = t.transform_normals(normals)
     points_out_expected = torch.bmm(points, R)
     normals_out_expected = torch.bmm(normals, R)
     self.assertTrue(torch.allclose(points_out, points_out_expected))
     self.assertTrue(torch.allclose(normals_out, normals_out_expected))
Exemplo n.º 11
0
 def test_se3_exp_zero_translation(self, batch_size: int = 100):
     """
     Check that `se3_exp_map` with zero translation gives
     the same result as corresponding `so3_exp_map`.
     """
     log_transform = TestSE3.init_log_transform(batch_size=batch_size)
     log_transform[:, :3] *= 0.0
     transform = se3_exp_map(log_transform, eps=1e-8)
     transform_so3 = so3_exp_map(log_transform[:, 3:], eps=1e-8)
     self.assertClose(transform[:, :3, :3],
                      transform_so3.permute(0, 2, 1),
                      atol=1e-4)
     self.assertClose(transform[:, 3, :3],
                      torch.zeros_like(transform[:, :3, 3]),
                      atol=1e-4)
Exemplo n.º 12
0
    def test_blender_camera(self):
        """
        Test BlenderCamera.
        """
        # Test get_world_to_view_transform.
        T = torch.randn(10, 3)
        R = so3_exp_map(torch.randn(10, 3) * 3.0)
        RT = get_world_to_view_transform(R=R, T=T)
        cam = BlenderCamera(R=R, T=T)
        RT_class = cam.get_world_to_view_transform()
        self.assertTrue(torch.allclose(RT.get_matrix(), RT_class.get_matrix()))
        self.assertTrue(isinstance(RT, Transform3d))

        # Test getting camera center.
        C = cam.get_camera_center()
        C_ = -torch.bmm(R, T[:, :, None])[:, :, 0]
        self.assertTrue(torch.allclose(C, C_, atol=1e-05))
Exemplo n.º 13
0
def init_random_cameras(cam_type: typing.Type[CamerasBase],
                        batch_size: int,
                        random_z: bool = False):
    cam_params = {}
    T = torch.randn(batch_size, 3) * 0.03
    if not random_z:
        T[:, 2] = 4
    R = so3_exp_map(torch.randn(batch_size, 3) * 3.0)
    cam_params = {"R": R, "T": T}
    if cam_type in (OpenGLPerspectiveCameras, OpenGLOrthographicCameras):
        cam_params["znear"] = torch.rand(batch_size) * 10 + 0.1
        cam_params[
            "zfar"] = torch.rand(batch_size) * 4 + 1 + cam_params["znear"]
        if cam_type == OpenGLPerspectiveCameras:
            cam_params["fov"] = torch.rand(batch_size) * 60 + 30
            cam_params["aspect_ratio"] = torch.rand(batch_size) * 0.5 + 0.5
        else:
            cam_params["top"] = torch.rand(batch_size) * 0.2 + 0.9
            cam_params["bottom"] = -(torch.rand(batch_size)) * 0.2 - 0.9
            cam_params["left"] = -(torch.rand(batch_size)) * 0.2 - 0.9
            cam_params["right"] = torch.rand(batch_size) * 0.2 + 0.9
    elif cam_type in (FoVPerspectiveCameras, FoVOrthographicCameras):
        cam_params["znear"] = torch.rand(batch_size) * 10 + 0.1
        cam_params[
            "zfar"] = torch.rand(batch_size) * 4 + 1 + cam_params["znear"]
        if cam_type == FoVPerspectiveCameras:
            cam_params["fov"] = torch.rand(batch_size) * 60 + 30
            cam_params["aspect_ratio"] = torch.rand(batch_size) * 0.5 + 0.5
        else:
            cam_params["max_y"] = torch.rand(batch_size) * 0.2 + 0.9
            cam_params["min_y"] = -(torch.rand(batch_size)) * 0.2 - 0.9
            cam_params["min_x"] = -(torch.rand(batch_size)) * 0.2 - 0.9
            cam_params["max_x"] = torch.rand(batch_size) * 0.2 + 0.9
    elif cam_type in (
            SfMOrthographicCameras,
            SfMPerspectiveCameras,
            OrthographicCameras,
            PerspectiveCameras,
    ):
        cam_params["focal_length"] = torch.rand(batch_size) * 10 + 0.1
        cam_params["principal_point"] = torch.randn((batch_size, 2))

    else:
        raise ValueError(str(cam_type))
    return cam_type(**cam_params)
Exemplo n.º 14
0
 def test_so3_exp_singularity(self, batch_size: int = 100):
     """
     Tests whether the `so3_exp_map` is robust to the input vectors
     the norms of which are close to the numerically unstable region
     (vectors with low l2-norms).
     """
     # generate random log-rotations with a tiny angle
     log_rot = TestSO3.init_log_rot(batch_size=batch_size)
     log_rot_small = log_rot * 1e-6
     log_rot_small.requires_grad = True
     R = so3_exp_map(log_rot_small)
     # tests whether all outputs are finite
     self.assertTrue(torch.isfinite(R).all())
     # tests whether the gradient is not None and all finite
     loss = R.sum()
     loss.backward()
     self.assertIsNotNone(log_rot_small.grad)
     self.assertTrue(torch.isfinite(log_rot_small.grad).all())
Exemplo n.º 15
0
 def compute_rots():
     so3_exp_map(log_rot)
     torch.cuda.synchronize()
    def _corresponding_cameras_alignment_test_case(
        self,
        cameras,
        R_align_gt,
        T_align_gt,
        s_align_gt,
        estimate_scale,
        mode,
        add_noise,
    ):
        batch_size = cameras.R.shape[0]

        # get target camera centers
        R_new = torch.bmm(R_align_gt[None].expand_as(cameras.R), cameras.R)
        T_new = (torch.bmm(T_align_gt[None, None].repeat(batch_size, 1, 1),
                           cameras.R)[:, 0] + cameras.T) * s_align_gt

        if add_noise != 0.0:
            R_new = torch.bmm(R_new,
                              so3_exp_map(torch.randn_like(T_new) * add_noise))
            T_new += torch.randn_like(T_new) * add_noise

        # create new cameras from R_new and T_new
        cameras_tgt = cameras.clone()
        cameras_tgt.R = R_new
        cameras_tgt.T = T_new

        # align cameras and cameras_tgt
        cameras_aligned = corresponding_cameras_alignment(
            cameras, cameras_tgt, estimate_scale=estimate_scale, mode=mode)

        if batch_size <= 2 and mode == "centers":
            # underdetermined case - check only the center alignment error
            # since the rotation and translation are ambiguous here
            self.assertClose(
                cameras_aligned.get_camera_center(),
                cameras_tgt.get_camera_center(),
                atol=max(add_noise * 7.0, 1e-4),
            )

        else:

            def _rmse(a):
                return (torch.norm(a, dim=1, p=2)**2).mean().sqrt()

            if add_noise != 0.0:
                # in a noisy case check mean rotation/translation error for
                # extrinsic alignment and root mean center error for center alignment
                if mode == "centers":
                    self.assertNormsClose(
                        cameras_aligned.get_camera_center(),
                        cameras_tgt.get_camera_center(),
                        _rmse,
                        atol=max(add_noise * 10.0, 1e-4),
                    )
                elif mode == "extrinsics":
                    angle_err = so3_relative_angle(cameras_aligned.R,
                                                   cameras_tgt.R,
                                                   cos_angle=True).mean()
                    self.assertClose(angle_err,
                                     torch.ones_like(angle_err),
                                     atol=add_noise * 0.03)
                    self.assertNormsClose(cameras_aligned.T,
                                          cameras_tgt.T,
                                          _rmse,
                                          atol=add_noise * 7.0)
                else:
                    raise ValueError(mode)

            else:
                # compare the rotations and translations of cameras
                self.assertClose(cameras_aligned.R, cameras_tgt.R, atol=3e-4)
                self.assertClose(cameras_aligned.T, cameras_tgt.T, atol=3e-4)
                # compare the centers
                self.assertClose(
                    cameras_aligned.get_camera_center(),
                    cameras_tgt.get_camera_center(),
                    atol=3e-4,
                )