def test_get_camera_intrinsics_exif(self):
     """Tests getter for intrinsics when explicit numpy arrays are absent and we fall back on exif."""
     loader = OlssonLoader(EXIF_FOLDER,
                           image_extension="JPG",
                           use_gt_intrinsics=False)
     computed = loader.get_camera_intrinsics(5)
     expected = Cal3Bundler(fx=2378.983, k1=0, k2=0, u0=648.0, v0=968.0)
     self.assertTrue(expected.equals(computed, 1e-3))
    def testSimpleTriangulationOnDoorDataset(self):
        """Test the tracks of the door dataset using simple triangulation initialization. Using computed tracks with
        ground truth camera params.

        Expecting failures on 2 tracks which have incorrect matches."""
        with open(DOOR_TRACKS_PATH, "rb") as handle:
            tracks = pickle.load(handle)

        loader = OlssonLoader(DOOR_DATASET_PATH, image_extension="JPG")

        camera_dict = {
            i: PinholeCameraCal3Bundler(loader.get_camera_pose(i),
                                        loader.get_camera_intrinsics(i))
            for i in range(len(loader))
        }

        initializer = Point3dInitializer(camera_dict,
                                         TriangulationParam.NO_RANSAC,
                                         reproj_error_thresh=1e5)

        # tracks which have expected failures
        # (both tracks have incorrect measurements)
        expected_failures = [
            SfmTrack2d(measurements=[
                SfmMeasurement(i=1,
                               uv=np.array([1252.22729492, 1487.29431152])),
                SfmMeasurement(i=2,
                               uv=np.array([1170.96679688, 1407.35876465])),
                SfmMeasurement(i=4, uv=np.array([263.32104492, 1489.76965332
                                                 ])),
            ]),
            SfmTrack2d(measurements=[
                SfmMeasurement(i=6, uv=np.array([1142.34545898, 735.92169189
                                                 ])),
                SfmMeasurement(i=7, uv=np.array([1179.84155273, 763.04095459
                                                 ])),
                SfmMeasurement(i=9, uv=np.array([216.54107666, 774.74017334])),
            ]),
        ]

        for track_2d in tracks:
            triangulated_track, _, _ = initializer.triangulate(track_2d)

            if triangulated_track is None:
                # assert we have failures which are already expected
                self.assertIn(track_2d, expected_failures)
class TestFolderLoader(unittest.TestCase):
    """Unit tests for folder loader, which loads image from a folder on disk."""
    def setUp(self):
        """Set up the loader for the test."""
        super().setUp()

        self.loader = OlssonLoader(str(DEFAULT_FOLDER), image_extension="JPG")

    def test_len(self):
        """Test the number of entries in the loader."""

        self.assertEqual(12, len(self.loader))

    def test_get_image_valid_index(self):
        """Tests that get_image works for all valid indices."""

        for idx in range(len(self.loader)):
            self.assertIsNotNone(self.loader.get_image(idx))

    def test_get_image_invalid_index(self):
        """Test that get_image raises an exception on an invalid index."""

        # negative index
        with self.assertRaises(IndexError):
            self.loader.get_image(-1)
        # len() as index
        with self.assertRaises(IndexError):
            self.loader.get_image(12)
        # index > len()
        with self.assertRaises(IndexError):
            self.loader.get_image(15)

    def test_image_contents(self):
        """Test the actual image which is being fetched by the loader at an index.

        This test's primary purpose is to check if the ordering of filename is being respected by the loader
        """
        index_to_test = 5
        file_path = DEFAULT_FOLDER / "images" / "DSC_0006.JPG"
        loader_image = self.loader.get_image(index_to_test)
        expected_image = io_utils.load_image(file_path)
        np.testing.assert_allclose(expected_image.value_array,
                                   loader_image.value_array)

    def test_get_camera_pose_exists(self):
        """Tests that the correct pose is fetched (present on disk)."""
        fetched_pose = self.loader.get_camera_pose(1)

        wRi_expected = np.array([
            [0.998079, 0.015881, 0.0598844],
            [-0.0161175, 0.999864, 0.00346851],
            [-0.0598212, -0.00442703, 0.998199],
        ])
        wti_expected = np.array([-0.826311, -0.00409053, 0.111315])

        expected_pose = Pose3(Rot3(wRi_expected), wti_expected)
        self.assertTrue(expected_pose.equals(fetched_pose, 1e-2))

    def test_get_camera_pose_missing(self):
        """Tests that the camera pose is None, because it is missing on disk."""
        loader = OlssonLoader(str(NO_EXTRINSICS_FOLDER), image_extension="JPG")
        fetched_pose = loader.get_camera_pose(5)
        self.assertIsNone(fetched_pose)

    def test_get_camera_intrinsics_explicit(self):
        """Tests getter for intrinsics when explicit data.mat file with intrinsics are present on disk."""
        expected_fx = 2398.119
        expected_fy = 2393.952
        expected_fx = min(expected_fx, expected_fy)

        expected_px = 628.265
        expected_py = 932.382

        computed = self.loader.get_camera_intrinsics(5)
        expected = Cal3Bundler(fx=expected_fx,
                               k1=0,
                               k2=0,
                               u0=expected_px,
                               v0=expected_py)

        self.assertTrue(expected.equals(computed, 1e-3))

    def test_get_camera_intrinsics_exif(self):
        """Tests getter for intrinsics when explicit numpy arrays are absent and we fall back on exif."""
        loader = OlssonLoader(EXIF_FOLDER,
                              image_extension="JPG",
                              use_gt_intrinsics=False)
        computed = loader.get_camera_intrinsics(5)
        expected = Cal3Bundler(fx=2378.983, k1=0, k2=0, u0=648.0, v0=968.0)
        self.assertTrue(expected.equals(computed, 1e-3))

    def test_get_camera_intrinsics_missing(self):
        """Tests getter for intrinsics when explicit numpy arrays are absent and we fall back on exif."""
        loader = OlssonLoader(NO_EXIF_FOLDER, image_extension="JPG")
        computed = loader.get_camera_intrinsics(5)
        self.assertIsNone(computed)

    def test_create_computation_graph_for_images(self):
        """Tests the graph for loading all the images."""
        image_graph = self.loader.create_computation_graph_for_images()

        # check the length of the graph
        self.assertEqual(12, len(image_graph))
        results = dask.compute(image_graph)[0]

        # randomly check image loads from a few indices
        np.testing.assert_allclose(results[5].value_array,
                                   self.loader.get_image(5).value_array)
        np.testing.assert_allclose(results[7].value_array,
                                   self.loader.get_image(7).value_array)

    def test_create_computation_graph_for_intrinsics(self):
        """Tests the graph for all intrinsics."""

        intrinsics_graph = self.loader.create_computation_graph_for_intrinsics(
        )

        # check the length of the graph
        self.assertEqual(12, len(intrinsics_graph))

        results = dask.compute(intrinsics_graph)[0]

        # randomly check intrinsics from a few indices
        self.assertTrue(
            self.loader.get_camera_intrinsics(5).equals(results[5], 1e-5))
        self.assertTrue(
            self.loader.get_camera_intrinsics(7).equals(results[7], 1e-5))
 def test_get_camera_intrinsics_missing(self):
     """Tests getter for intrinsics when explicit numpy arrays are absent and we fall back on exif."""
     loader = OlssonLoader(NO_EXIF_FOLDER, image_extension="JPG")
     computed = loader.get_camera_intrinsics(5)
     self.assertIsNone(computed)