def test_benchmark_results_estimates_no_error_for_noiseless_trajectory(
            self):
        # Create a new computed trajectory with no noise, but a fixed offset from the real trajectory
        # That is, the relative motions are the same, but the start point is different
        for trial_result in self.trial_results:
            comp_traj, _ = create_noise(
                trajectory=trial_result.ground_truth_trajectory,
                random_state=self.random,
                time_offset=0,
                time_noise=0,
                loc_noise=0,
                rot_noise=0)
            trial_result.computed_trajectory = comp_traj

        benchmark = feb.FrameErrorsBenchmark()
        result = benchmark.benchmark_results(self.trial_results)

        # Check all the errors are zero
        values = collect_values(result, 0)
        self.assertNPClose(np.zeros(values.shape), values)
        values = collect_values(result, 1)
        self.assertNPClose(np.zeros(values.shape), values)
        values = collect_values(result, 2)
        self.assertNPClose(np.zeros(values.shape), values, atol=1e-7)
        values = collect_values(result, 3)
        self.assertNPClose(np.zeros(values.shape), values, atol=1e-7)
 def test_benchmark_results_estimates_reasonable_trajectory_error_per_frame(
         self):
     benchmark = feb.FrameErrorsBenchmark()
     result = benchmark.benchmark_results(self.trial_results)
     # The noise added to each location is <10, converting to motions makes that <20, in each axis
     # But then, changes to the orientation tweak the relative location, and hence the motion
     self.assertLessEqual(np.max(collect_values(result, 0)), 100)
     self.assertLessEqual(np.max(collect_values(result, 2)), np.pi / 32)
 def test_benchmark_results_returns_a_benchmark_result(self):
     benchmark = feb.FrameErrorsBenchmark()
     result = benchmark.benchmark_results(self.trial_results)
     self.assertIsInstance(result, arvet.core.benchmark.BenchmarkResult)
     self.assertNotIsInstance(result, arvet.core.benchmark.FailedBenchmark)
     self.assertEqual(benchmark.identifier, result.benchmark)
     self.assertEqual(
         set(trial_result.identifier
             for trial_result in self.trial_results),
         set(result.trial_results))
    def test_benchmark_results_one_observation_per_frame(self):
        benchmark = feb.FrameErrorsBenchmark()
        result = benchmark.benchmark_results(self.trial_results)

        if isinstance(result, arvet.core.benchmark.FailedBenchmark):
            print(result.reason)

        self.assertEqual(
            len(self.trial_results[0].ground_truth_trajectory) - 1,
            len(result.frame_errors))
        for error_measurement in result.frame_errors.values():
            self.assertEqual(18, len(error_measurement))
    def test_benchmark_results_fails_for_trials_from_different_systems(self):
        trajectory = create_random_trajectory(self.random)
        mixed_trial_results = self.trial_results + [
            MockTrialResult(gt_trajectory=trajectory,
                            comp_trajectory=trajectory,
                            system_id=bson.ObjectId())
        ]

        # Perform the benchmark
        benchmark = feb.FrameErrorsBenchmark()
        result = benchmark.benchmark_results(mixed_trial_results)
        self.assertIsInstance(result, arvet.core.benchmark.FailedBenchmark)
    def test_benchmark_results_estimates_no_noise_for_identical_trajectory(
            self):
        # Make all the trial results have exactly the same computed trajectories
        for trial_result in self.trial_results[1:]:
            trial_result.computed_trajectory = copy.deepcopy(
                self.trial_results[0].computed_trajectory)

        benchmark = feb.FrameErrorsBenchmark()
        result = benchmark.benchmark_results(self.trial_results)

        # Check all the errors are zero
        values = collect_values(result, 4)
        self.assertNPClose(np.zeros(values.shape), values)
        values = collect_values(result, 5)
        self.assertNPClose(np.zeros(values.shape), values)
        values = collect_values(result, 6)
        self.assertNPClose(np.zeros(values.shape), values, atol=1e-7)
        values = collect_values(result, 7)
        self.assertNPClose(np.zeros(values.shape), values, atol=1e-7)
    def test_benchmark_results_estimates_no_error_for_identical_trajectory(
            self):
        # Copy the ground truth exactly
        for trial_result in self.trial_results:
            trial_result.computed_trajectory = copy.deepcopy(
                trial_result.ground_truth_trajectory)

        benchmark = feb.FrameErrorsBenchmark()
        result = benchmark.benchmark_results(self.trial_results)

        if isinstance(result, arvet.core.benchmark.FailedBenchmark):
            print(result.reason)

        # Check all the errors are zero
        values = collect_values(result, 0)
        self.assertNPClose(np.zeros(values.shape), values)
        values = collect_values(result, 1)
        self.assertNPClose(np.zeros(values.shape), values)
        # We need more tolerance for the rotational error, because of the way the arccos
        # results in the smallest possible change producing a value around 2e-8
        values = collect_values(result, 2)
        self.assertNPClose(np.zeros(values.shape), values, atol=1e-7)
        values = collect_values(result, 3)
        self.assertNPClose(np.zeros(values.shape), values, atol=1e-7)
    def test_benchmark_results_fails_for_no_observations(self):
        # Adjust the computed timestamps so none of them match
        for trial_result in self.trial_results:
            trial_result.computed_trajectory = {
                time + 10000: pose
                for time, pose in trial_result.computed_trajectory.items()
            }
            trial_result.tracking_states = {
                time + 10000: state
                for time, state in trial_result.tracking_states.items()
            }
            trial_result.num_features = {
                time + 10000: features
                for time, features in trial_result.num_features.items()
            }
            trial_result.num_matches = {
                time + 10000: features
                for time, features in trial_result.num_matches.items()
            }

        # Perform the benchmark
        benchmark = feb.FrameErrorsBenchmark()
        result = benchmark.benchmark_results(self.trial_results)
        self.assertIsInstance(result, arvet.core.benchmark.FailedBenchmark)
    def do_imports(self,
                   task_manager: arvet.batch_analysis.task_manager.TaskManager,
                   path_manager: arvet.config.path_manager.PathManager,
                   db_client: arvet.database.client.DatabaseClient):
        """
        Import image sources for evaluation in this experiment
        :param task_manager: The task manager, for creating import tasks
        :param path_manager: The path manager, for resolving file system paths
        :param db_client: The database client, for saving declared objects too small to need a task
        :return:
        """

        # --------- SIMULATORS -----------
        # Add simulators explicitly, they have different metadata, so we can't just search
        for exe, world_name, environment_type, light_level, time_of_day in [
            ('simulators/AIUE_V01_001/LinuxNoEditor/tempTest/Binaries/Linux/tempTest',
             'AIUE_V01_001', imeta.EnvironmentType.INDOOR,
             imeta.LightingLevel.WELL_LIT, imeta.TimeOfDay.DAY),
            ('simulators/AIUE_V01_002/LinuxNoEditor/tempTest/Binaries/Linux/tempTest',
             'AIUE_V01_002', imeta.EnvironmentType.INDOOR,
             imeta.LightingLevel.WELL_LIT, imeta.TimeOfDay.DAY),
            ('simulators/AIUE_V01_003/LinuxNoEditor/tempTest/Binaries/Linux/tempTest',
             'AIUE_V01_003', imeta.EnvironmentType.INDOOR,
             imeta.LightingLevel.WELL_LIT, imeta.TimeOfDay.DAY),
            ('simulators/AIUE_V01_004/LinuxNoEditor/tempTest/Binaries/Linux/tempTest',
             'AIUE_V01_004', imeta.EnvironmentType.INDOOR,
             imeta.LightingLevel.WELL_LIT, imeta.TimeOfDay.DAY),
            (
                'simulators/AIUE_V01_005/LinuxNoEditor/tempTest/Binaries/Linux/tempTest',
                'AIUE_V01_005', imeta.EnvironmentType.INDOOR,
                imeta.LightingLevel.WELL_LIT, imeta.TimeOfDay.DAY
                # ), (
                #         'simulators/AIUE_V02_001/LinuxNoEditor/tempTest/Binaries/Linux/tempTest',
                #         'AIUE_V02_001', imeta.EnvironmentType.INDOOR, imeta.LightingLevel.WELL_LIT,
                #         imeta.TimeOfDay.DAY
            )
        ]:
            self.import_simulator(executable_path=exe,
                                  world_name=world_name,
                                  environment_type=environment_type,
                                  light_level=light_level,
                                  time_of_day=time_of_day,
                                  db_client=db_client)

        # --------- REAL WORLD DATASETS -----------

        # Import EuRoC datasets with lists of trajectory start points for each simulator
        for name, path, mappings in [
            ('EuRoC MH_01_easy', os.path.join('datasets', 'EuRoC',
                                              'MH_01_easy'),
             euroc_origins.get_MH_01_easy()),
            ('EuRoC MH_02_easy', os.path.join('datasets', 'EuRoC',
                                              'MH_02_easy'),
             euroc_origins.get_MH_02_easy()),
            ('EuRoC MH_03_medium',
             os.path.join('datasets', 'EuRoC',
                          'MH_03_medium'), euroc_origins.get_MH_03_medium()),
            ('EuRoC MH_04_difficult',
             os.path.join('datasets', 'EuRoC', 'MH_04_difficult'),
             euroc_origins.get_MH_04_difficult()),
            ('EuRoC MH_05_difficult',
             os.path.join('datasets', 'EuRoC', 'MH_05_difficult'),
             euroc_origins.get_MH_05_difficult()),
            ('EuRoC V1_01_easy', os.path.join('datasets', 'EuRoC',
                                              'V1_01_easy'),
             euroc_origins.get_V1_01_easy()),
            ('EuRoC V1_02_medium',
             os.path.join('datasets', 'EuRoC',
                          'V1_02_medium'), euroc_origins.get_V1_02_medium()),
            ('EuRoC V1_03_difficult',
             os.path.join('datasets', 'EuRoC', 'V1_03_difficult'),
             euroc_origins.get_V1_03_difficult()),
            ('EuRoC V2_01_easy', os.path.join('datasets', 'EuRoC',
                                              'V2_01_easy'),
             euroc_origins.get_V2_01_easy()),
            ('EuRoC V2_02_medium',
             os.path.join('datasets', 'EuRoC',
                          'V2_02_medium'), euroc_origins.get_V2_02_medium()),
            ('EuRoC V2_03_difficult',
             os.path.join('datasets', 'EuRoC', 'V2_03_difficult'),
             euroc_origins.get_V2_03_difficult())
        ]:
            self.import_dataset(
                module_name='arvet_slam.dataset.euroc.euroc_loader',
                path=path,
                name=name,
                mappings=mappings,
                task_manager=task_manager,
                path_manager=path_manager)

        # Import TUM datasets with lists of trajectory start points for each simulator
        for folder, mappings in [
            ('rgbd_dataset_freiburg1_360', tum_origins.get_frieburg1_360()),
            ('rgbd_dataset_frieburg1_rpy', tum_origins.get_frieburg1_rpy()),
            ('rgbd_dataset_frieburg1_xyz', tum_origins.get_frieburg1_xyz()),
            ('rgbd_dataset_frieburg2_desk', tum_origins.get_frieburg2_desk()),
            ('rgbd_dataset_frieburg2_rpy', tum_origins.get_frieburg2_rpy()),
            ('rgbd_dataset_frieburg2_xyz', tum_origins.get_frieburg2_xyz()),
            ('rgbd_dataset_frieburg3_structure_texture_far',
             tum_origins.get_frieburg3_structure_texture_far()),
            ('rgbd_dataset_frieburg3_walking_xyz',
             tum_origins.get_frieburg3_walking_xyz())
        ]:
            self.import_dataset(
                module_name='arvet_slam.dataset.tum.tum_loader',
                path=os.path.join('datasets', 'TUM', folder),
                name="TUM {0}".format(folder),
                mappings=mappings,
                task_manager=task_manager,
                path_manager=path_manager)

        # Import KITTI datasets
        for sequence_num in range(11):
            self.import_dataset(
                module_name='arvet_slam.dataset.kitti.kitti_loader',
                name='KITTI trajectory {}'.format(sequence_num),
                path=os.path.join('datasets', 'KITTI', 'dataset'),
                additional_args={'sequence_number': sequence_num},
                mappings=kitti_origins.get_mapping(sequence_num),
                task_manager=task_manager,
                path_manager=path_manager)

        # --------- SYSTEMS -----------
        # LibVisO2
        self.import_system(name='LibVisO',
                           system=libviso2.LibVisOSystem(),
                           db_client=db_client)

        # ORBSLAM2 - Create 2 variants, stereo and mono
        # These datasets don't have
        vocab_path = os.path.join('systems', 'ORBSLAM2', 'ORBvoc.txt')
        for sensor_mode in {
                orbslam2.SensorMode.STEREO, orbslam2.SensorMode.MONOCULAR,
                orbslam2.SensorMode.RGBD
        }:
            self.import_system(
                name='ORBSLAM2 {mode}'.format(mode=sensor_mode.name.lower()),
                system=orbslam2.ORBSLAM2(
                    vocabulary_file=vocab_path,
                    mode=sensor_mode,
                    settings={'ORBextractor': {
                        'nFeatures': 1500
                    }}),
                db_client=db_client)

        # --------- BENCHMARKS -----------
        # Add benchmarks to calculate the errors on a per-estimate and per-frame basis
        self.import_benchmark(
            name='Estimate Errors',
            benchmark=estimate_errors_benchmark.EstimateErrorsBenchmark(),
            db_client=db_client)
        self.import_benchmark(
            name='Frame Errors',
            benchmark=frame_errors_benchmark.FrameErrorsBenchmark(),
            db_client=db_client)

        # --------- TRAJECTORY GROUPS -----------
        # Update the trajectory groups
        # We call this at the end so that any new ones created by import datasets will be updated and saved.
        for trajectory_group in self.trajectory_groups.values():
            self.update_trajectory_group(trajectory_group, task_manager,
                                         db_client)
 def make_instance(self, *args, **kwargs):
     return feb.FrameErrorsBenchmark(*args, **kwargs)