Esempio n. 1
0
    def test_export(self):
        # the rig
        rigs = kapture.Rigs()
        rigs['rig0', get_camera_kapture_id_from_colmap_id(0)] = kapture.PoseTransform()
        rigs['rig0', get_camera_kapture_id_from_colmap_id(1)] = kapture.PoseTransform()
        # the records
        records_camera = kapture.RecordsCamera()
        records_camera[0, get_camera_kapture_id_from_colmap_id(0)] = 'camL/0000.jpg'
        records_camera[0, get_camera_kapture_id_from_colmap_id(1)] = 'camR/0000.jpg'
        records_camera[1, get_camera_kapture_id_from_colmap_id(0)] = 'camL/0001.jpg'
        records_camera[1, get_camera_kapture_id_from_colmap_id(1)] = 'camR/0001.jpg'
        # expect
        expected_rigs = [{
            "cameras": [
                {
                    "camera_id": 0,
                    "image_prefix": "camL"
                },
                {
                    "camera_id": 1,
                    "image_prefix": "camR"
                }
            ],
            "ref_camera_id": 0
        }]

        colmap_camera_ids = {get_camera_kapture_id_from_colmap_id(i): i for i in range(2)}
        colmap_rigs = export_colmap_rig_json(rigs, records_camera, colmap_camera_ids)
        self.assertEqual(colmap_rigs, expected_rigs)
Esempio n. 2
0
def merge_rigs(rigs_list: List[Optional[kapture.Rigs]],
               rig_mappings: List[Dict[str, str]],
               sensor_mappings: List[Dict[str, str]]) -> kapture.Rigs:
    """
    Merge several rigs list into one list with new identifiers for the rigs and the sensors.

    :param rigs_list: list of rigs definitions to merge
    :param rig_mappings: mapping of the rigs identifiers to their new identifiers
    :param sensor_mappings: mapping of the sensor identifiers to their new identifiers
    :return: merged rigs definitions
    """
    assert len(rigs_list) > 0
    assert len(rigs_list) == len(rig_mappings)
    assert len(rigs_list) == len(sensor_mappings)

    merged_rigs = kapture.Rigs()
    for rigs, rig_mapping, sensor_mapping in zip(rigs_list, rig_mappings,
                                                 sensor_mappings):
        if rigs is None:
            continue
        for rig_id, sensor_id in rigs.key_pairs():
            new_rig_id = rig_mapping[rig_id]
            new_sensor_id = sensor_mapping[sensor_id]
            merged_rigs[(new_rig_id, new_sensor_id)] = rigs[(rig_id,
                                                             sensor_id)]
    return merged_rigs
Esempio n. 3
0
 def test_kapture_write_read(self):
     kdata_expected = kapture.Kapture()
     kdata_expected.sensors = kapture.Sensors()
     kdata_expected.trajectories = kapture.Trajectories()
     kdata_expected.rigs = kapture.Rigs()
     csv.kapture_to_dir(self._tempdir.name, kdata_expected)
     kdata_actual = csv.kapture_from_dir(self._tempdir.name)
Esempio n. 4
0
 def test_rig_remove(self):
     rigs = kapture.Rigs()
     rigs['rig0', 'cam0'] = kapture.PoseTransform(r=[1, 0, 0, 0],
                                                  t=[100, 0, 0])
     rigs['rig0', 'cam1'] = kapture.PoseTransform(r=[1, 0, 0, 0],
                                                  t=[-100, 0, 0])
     trajectories = kapture.Trajectories()
     trajectories[0, 'rig0'] = kapture.PoseTransform(r=[1, 0, 0, 0],
                                                     t=[0, 0, 0])
     trajectories[1, 'rig0'] = kapture.PoseTransform(r=[1, 0, 0, 0],
                                                     t=[0, 0, 10])
     trajectories[2, 'rig0'] = kapture.PoseTransform(r=[1, 0, 0, 0],
                                                     t=[0, 0, 20])
     trajectories_ = kapture.rigs_remove(trajectories, rigs)
     # timestamps should be unchanged
     self.assertEqual(trajectories_.keys(), trajectories.keys())
     self.assertNotEqual(trajectories_.key_pairs(),
                         trajectories.key_pairs())
     self.assertEqual(len(trajectories_.key_pairs()),
                      len(trajectories.key_pairs()) * len(rigs.key_pairs()))
     self.assertIn((0, 'cam0'), trajectories_.key_pairs())
     self.assertIn((0, 'cam1'), trajectories_.key_pairs())
     self.assertIn((2, 'cam0'), trajectories_.key_pairs())
     self.assertIn((2, 'cam1'), trajectories_.key_pairs())
     self.assertAlmostEqual(trajectories_[2, 'cam1'].t_raw,
                            [-100.0, 0.0, 20.0])
     self.assertAlmostEqual(trajectories_[2, 'cam1'].r_raw,
                            [1.0, 0.0, 0.0, 0.0])
Esempio n. 5
0
    def setUp(self):
        self._rigs = kapture.Rigs()
        looking_not_straight = quaternion.from_rotation_vector(
            [0, np.deg2rad(5.), 0])
        self._rigs['rig', 'cam1'] = kapture.PoseTransform(
            t=[-10, 0, 0], r=looking_not_straight).inverse()
        self._rigs['rig', 'cam2'] = kapture.PoseTransform(
            t=[+10, 0, 0], r=looking_not_straight.inverse()).inverse()
        self._trajectories_rigs = kapture.Trajectories()
        for timestamp, ratio in enumerate(np.linspace(0., 1., num=8)):
            looking_around = quaternion.from_rotation_vector(
                [0, np.deg2rad(360. * ratio), 0])
            self._trajectories_rigs[timestamp, 'rig'] = kapture.PoseTransform(
                t=[0, 0, -100.], r=looking_around)

        self._trajectories_cams = kapture.Trajectories()
        for timestamp, rig_id, pose_rig_from_world in kapture.flatten(
                self._trajectories_rigs, is_sorted=True):
            for rig_id2, cam_id, pose_cam_from_rig in kapture.flatten(
                    self._rigs):
                assert rig_id == rig_id
                pose_cam_from_world = kapture.PoseTransform.compose(
                    [pose_cam_from_rig, pose_rig_from_world])
                self._trajectories_cams[timestamp,
                                        cam_id] = pose_cam_from_world
Esempio n. 6
0
    def test_kapture_write(self):
        kdata = kapture.Kapture()

        # test it is not writing files for undefined parts
        csv.kapture_to_dir(self._tempdir.name, kdata)
        self.assertFalse(
            path.exists(path.join(self._tempdir.name, 'sensors',
                                  'sensors.txt')))
        self.assertFalse(
            path.exists(
                path.join(self._tempdir.name, 'sensors', 'trajectories.txt')))
        self.assertFalse(
            path.exists(path.join(self._tempdir.name, 'sensors', 'rigs.txt')))

        # test it is actually writing files for parts
        kdata.sensors = kapture.Sensors()
        kdata.trajectories = kapture.Trajectories()
        kdata.rigs = kapture.Rigs()
        csv.kapture_to_dir(self._tempdir.name, kdata)
        self.assertTrue(
            path.exists(path.join(self._tempdir.name, 'sensors',
                                  'sensors.txt')))
        self.assertTrue(
            path.exists(
                path.join(self._tempdir.name, 'sensors', 'trajectories.txt')))
        self.assertTrue(
            path.exists(path.join(self._tempdir.name, 'sensors', 'rigs.txt')))
Esempio n. 7
0
def rigs_from_file(filepath: str, sensor_ids: Set[str]) -> kapture.Rigs:
    """
    Reads rigs from CSV file.

    :param filepath: input file path
    :param sensor_ids: input set of valid sensor ids.
                        If a rig id collides one of them, raise error.
                        If a sensor in rig is not in sensor_ids, it is ignored.
    :return: rigs
    """
    # rig_id, sensor_id, qw, qx, qy, qz, tx, ty, tz
    rigs = kapture.Rigs()
    with open(filepath) as file:
        table = table_from_file(file)
        for rig_id, sensor_id, qw, qx, qy, qz, tx, ty, tz in table:
            if rig_id in sensor_ids:
                raise ValueError(f'collision between a sensor ID and rig ID ({rig_id})')
            if sensor_id not in sensor_ids:
                # just ignore
                continue
            rotation = float_array_or_none([qw, qx, qy, qz])
            translation = float_array_or_none([tx, ty, tz])
            pose = kapture.PoseTransform(rotation, translation)
            # rigs.setdefault(str(rig_id), kapture.Rig())[sensor_id] = pose
            rigs[str(rig_id), sensor_id] = pose
    return rigs
def import_robotcar_rig(extrinsics_dir_path: str) -> kapture.Rigs:
    """
    Read extrinsics files and convert to kapture rigs
    :param extrinsics_dir_path: path to directory with extrinsics
    :return: kapture.Rigs object
    """
    # From dataset documentation:
    #   The extrinsic parameters of the three cameras on the car with respect to the car itself.
    #   The extrinsics are provided as a 4x4 matrix
    #     [R c]
    #     [0 1]
    #   where R is a rotation matrix that maps from camera to world coordinates and c is the position of the camera in
    #   world coordinates. The entries of the matrix are separated by ,.

    rigs = kapture.Rigs()
    for root, dirs, files in os.walk(extrinsics_dir_path):
        for extrinsics_filepath in files:
            (camera_id, _) = extrinsics_filepath.split('_')
            extrinsic_file = open(
                path.join(extrinsics_dir_path, extrinsics_filepath), 'r')
            with extrinsic_file as f:
                m = np.array([[float(num) for num in line.split(',')]
                              for line in f])
            rotation_matrix = m[0:3, 0:3]
            position = m[0:3, 3:4]
            pose_transform = kapture.PoseTransform(
                t=position, r=quaternion.from_rotation_matrix(rotation_matrix))
            # kapture rig format is "rig to sensor"
            rigs['car', camera_id] = pose_transform.inverse()

    return rigs
Esempio n. 9
0
    def test_type_checking(self):
        rigs = kapture.Rigs()
        valid_id, valid_pose = 'rig0', kapture.PoseTransform()
        invalid_id, invalid_pose = float(0), 'rig'

        self.assertRaises(TypeError, rigs.__setitem__, valid_id, valid_pose)
        self.assertRaises(TypeError, rigs.__setitem__, (valid_id, invalid_id), valid_pose)
        self.assertRaises(TypeError, rigs.__setitem__, (invalid_id, valid_id), valid_pose)
        self.assertRaises(TypeError, rigs.__setitem__, (valid_id, valid_id), invalid_pose)
Esempio n. 10
0
 def test_init(self):
     rigs = kapture.Rigs()
     rigs['rig0', 'cam0'] = kapture.PoseTransform()
     rigs['rig0', 'cam1'] = kapture.PoseTransform()
     rigs['rig1'] = {
         'cam2': kapture.PoseTransform(),
         'cam3': kapture.PoseTransform()
     }
     self.assertEqual(2, len(rigs))
     self.assertIn('rig0', rigs)
     self.assertIn('rig1', rigs)
     self.assertIn('cam0', rigs['rig0'])
     self.assertNotIn('cam0', rigs['rig1'])
Esempio n. 11
0
    def test_rig_write(self):
        rigs = kapture.Rigs()
        rigs['rig1', 'cam0'] = kapture.PoseTransform()
        rigs['rig1', 'cam1'] = kapture.PoseTransform(r=[0.5, 0.5, 0.5, 0.5])
        content_expected = '\n'.join([csv.KAPTURE_FORMAT_1,
                                      '# rig_id, sensor_id, qw, qx, qy, qz, tx, ty, tz',
                                      'rig1, cam0,  1.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0',
                                      'rig1, cam1,  0.5,  0.5,  0.5,  0.5,  0.0,  0.0,  0.0',
                                      ''])

        csv.rigs_to_file(self._temp_filepath, rigs)
        with open(self._temp_filepath, 'rt') as f:
            content_actual = ''.join(f.readlines())
        self.assertEqual(content_expected, content_actual)
Esempio n. 12
0
def _make_rigs(replace_pose_rig, trajectories) -> kapture.Rigs:
    logger.info('Making up a rig ...')
    rigs = kapture.Rigs()
    pose_babord = kapture.PoseTransform(t=[0, 0, 0],
                                        r=quaternion.from_rotation_vector(
                                            [0, -np.pi / 2, 0]))
    pose_tribord = kapture.PoseTransform(t=[0, 0, 0],
                                         r=quaternion.from_rotation_vector(
                                             [0, np.pi / 2, 0]))
    rigs['silda_rig', '0'] = pose_babord
    rigs['silda_rig', '1'] = pose_tribord
    if replace_pose_rig:
        logger.info('replacing camera poses with rig poses.')
        kapture.rigs_recover_inplace(trajectories, rigs)
    return rigs
Esempio n. 13
0
    def setUp(self):
        self._samples_folder = path.abspath(
            path.join(path.dirname(__file__), '..', 'samples', 'm1x'))
        self._kapture_data = csv.kapture_from_dir(self._samples_folder)

        rotation_a = quaternion.quaternion(-0.572, 0.198, 0.755, -0.252)
        rotation_b = quaternion.quaternion(0.878, 0.090, 0.374, -0.285)
        translation_a = [144.801, -74.548, -17.746]
        translation_b = [144.701, -73.548, -17.746]
        self._pose_a = kapture.PoseTransform(rotation_a, translation_a)
        self._pose_b = kapture.PoseTransform(rotation_b, translation_b)

        self._rigs = kapture.Rigs()
        self._rigs['rig_a', '144323'] = self._pose_a
        self._rigs['rig_b', '144323'] = self._pose_b
Esempio n. 14
0
def merge_rigs(rigs_list: List[Optional[kapture.Rigs]]) -> kapture.Rigs:
    """
    Merge several rigs lists. For sensor with the same rig and sensor identifier, keep only the first one.

    :param rigs_list: list of rigs
    :return: merged rigs
    """
    assert len(rigs_list) > 0

    merged_rigs = kapture.Rigs()
    for rigs in rigs_list:
        if rigs is None:
            continue
        for rig_id, sensor_id in rigs.key_pairs():
            if rig_id in merged_rigs and sensor_id in merged_rigs[rig_id]:
                continue
            merged_rigs[(rig_id, sensor_id)] = rigs[(rig_id, sensor_id)]
    return merged_rigs
Esempio n. 15
0
def import_7scenes(d7scenes_path: str,
                   kapture_dir_path: str,
                   force_overwrite_existing: bool = False,
                   images_import_method: TransferAction = TransferAction.skip,
                   partition: Optional[str] = None
                   ) -> None:
    """
    Imports RGB-D Dataset 7-Scenes dataset and save them as kapture.

    :param d7scenes_path: path to the 7scenes sequence root path
    :param kapture_dir_path: path to kapture top directory
    :param force_overwrite_existing: Silently overwrite kapture files if already exists.
    :param images_import_method: choose how to import actual image files.
    :param partition: if specified = 'mapping' or 'query'. Requires d7scenes_path/TestSplit.txt or TrainSplit.txt
                    to exists.
    """
    os.makedirs(kapture_dir_path, exist_ok=True)
    delete_existing_kapture_files(kapture_dir_path, force_erase=force_overwrite_existing)

    logger.info('loading all content ...')

    d7s_filename_re = re.compile(r'((?P<sequence>.+)/)?frame-(?P<frame_id>\d{6})\.(?P<suffix>\w*)\.(?P<ext>\w*)')

    # populate all relevant files
    d7s_filenames = (path_secure(path.relpath(path.join(dp, fn), d7scenes_path))
                     for dp, _, fs in os.walk(d7scenes_path) for fn in fs)

    logger.info('populating 7-scenes files ...')
    d7s_filenames = {filename: d7s_filename_re.search(filename).groupdict()
                     for filename in sorted(d7s_filenames)
                     if d7s_filename_re.search(filename)}

    # reorg as shot[seq, id] = {color: , depth: , pose: , ...}
    shots = {}
    for timestamp, (filename, file_attribs) in enumerate(d7s_filenames.items()):
        shot_id = (file_attribs.get('sequence'), file_attribs['frame_id'])
        shots.setdefault(shot_id, {})[file_attribs['suffix']] = filename

    # fake timestamps
    for timestamp, shot_id in enumerate(shots):
        shots[shot_id]['timestamp'] = timestamp

    # if given, filter partition
    if partition is not None:
        # read the authors split file
        partition_filepath = path.join(d7scenes_path, PARTITION_FILENAMES[partition])
        if not path.isfile(partition_filepath):
            raise FileNotFoundError(f'partition file is missing: {partition_filepath}.')
        with open(partition_filepath, 'rt') as file:
            split_sequences = [f'seq-{int(seq.strip()[len("sequence"):]):02}' for seq in file.readlines()]
        assert len(split_sequences) > 0
        # filter out
        shots = {(seq, frame): shot
                 for (seq, frame), shot in shots.items()
                 if seq in split_sequences}

    if len(shots) == 0:
        raise FileNotFoundError('no file found: make sure the path to 7scenes sequence is valid.')

    # eg. shots['seq-01', '000000'] =
    #       {
    #           'color': 'seq-01/frame-000000.color.jpg',
    #           'depth': 'seq-01/frame-000000.depth.png',
    #           'pose': 'seq-01/frame-000000.pose.txt',
    #           'timestamp': 0}

    # images + depth maps
    logger.info('populating image and depth maps files ...')
    snapshots = kapture.RecordsCamera()
    depth_maps = kapture.RecordsDepth()
    for shot in shots.values():
        snapshots[shot['timestamp'], RGB_SENSOR_ID] = shot['color']
        kapture_depth_map_filename = shot['depth'][:-len('.png')]  # kapture depth files are not png
        depth_maps[shot['timestamp'], DEPTH_SENSOR_ID] = kapture_depth_map_filename
        kapture_registered_depth_map_filename = shot['depth'][:-len('.png')] + '.reg'  # kapture depth files are not png
        depth_maps[shot['timestamp'], REG_DEPTH_SENSOR_ID] = kapture_registered_depth_map_filename

    # poses
    logger.info('import poses files ...')
    trajectories = kapture.Trajectories()
    for shot in shots.values():
        pose_filepath = path.join(d7scenes_path, shot['pose'])
        pose_mat = np.loadtxt(pose_filepath)  # camera-to-world, 4×4 matrix in homogeneous coordinates
        rotation_mat = pose_mat[0:3, 0:3]
        position_vec = pose_mat[0:3, 3]
        rotation_quat = quaternion.from_rotation_matrix(rotation_mat)
        pose_world_from_cam = kapture.PoseTransform(r=rotation_quat, t=position_vec)
        pose_cam_from_world = pose_world_from_cam.inverse()
        trajectories[shot['timestamp'], RGBD_SENSOR_ID] = pose_cam_from_world

    # sensors
    """
    From authors: The RGB and depth camera have not been calibrated and we can’t provide calibration parameters at the
    moment. The recorded frames correspond to the raw, uncalibrated camera images. In the KinectFusion pipeline we used
    the following default intrinsics for the depth camera: Principle point (320,240), Focal length (585,585).    
    ----
    We use the extr. kinect camera parameters from https://projet.liris.cnrs.fr/voir/activities-dataset/kinect-calibration.html. 
    """
    sensors = kapture.Sensors()
    # camera_type = kapture.CameraType.OPENCV
    # camera_params = [640, 480, 5.2161910696979987e+02, 5.2132946256749767e+02, 3.1755491910920682e+02, 2.5921654718027673e+02,
    #                  2.5673002693536984e-01, -9.3976085633794137e-01, -1.8605549188751580e-03, -2.2232238578189420e-03]  # w, h, f, cx, cy, k1, k2, p1, p2, k3
    camera_type = kapture.CameraType.SIMPLE_PINHOLE
    # camera_params = [640, 480, 5.2161910696979987e+02, 5.2132946256749767e+02, 3.1755491910920682e+02, 2.5921654718027673e+02]  # w, h, fx, fy, cx, cy
    camera_params = [640, 480, 525, 320, 240]  # w, h, f, cx, cy
    sensors[RGB_SENSOR_ID] = kapture.Camera(
        name=RGB_SENSOR_ID,
        camera_type=camera_type,
        camera_params=camera_params
    )
    # depth_camera_type = kapture.CameraType.OPENCV
    # depth_camera_params = [640, 480, 5.8818670481438744e+02, 5.8724220649505514e+02, 3.1076280589210484e+02, 2.2887144980135292e+02,
    #                        -1.8932947734719333e-01, 1.1358015104098631e+00, -4.4260345347128536e-03, -5.4869578635708153e-03, -2.2460143607712921e+00] # w, h, f, cx, cy, k1, k2, p1, p2, k3
    depth_camera_type = kapture.CameraType.SIMPLE_PINHOLE
    # depth_camera_params = [640, 480, 5.8818670481438744e+02, 5.8724220649505514e+02, 3.1076280589210484e+02, 2.2887144980135292e+02] # w, h, fx, fy, cx, cy
    depth_camera_params = [640, 480, 585, 320, 240]  # w, h, f, cx, cy
    sensors[DEPTH_SENSOR_ID] = kapture.Camera(
        name=DEPTH_SENSOR_ID,
        camera_type=depth_camera_type,
        camera_params=depth_camera_params,
        sensor_type='depth'
    )
    sensors[REG_DEPTH_SENSOR_ID] = kapture.Camera(
        name=REG_DEPTH_SENSOR_ID,
        camera_type=depth_camera_type,
        camera_params=camera_params,
        sensor_type='depth'
    )

    # bind camera and depth sensor into a rig
    R = np.array([[9.9996518012567637e-01, 2.6765126468950343e-03, -7.9041012313000904e-03],
                  [-2.7409311281316700e-03, 9.9996302803027592e-01, -8.1504520778013286e-03],
                  [7.8819942130445332e-03, 8.1718328771890631e-03, 9.9993554558014031e-01]])
    T = np.array([-2.5558943178152542e-02, 1.0109636268061706e-04, 2.0318321729487039e-03])
    Rt = np.vstack((np.hstack((R, T.reshape(3, 1))), np.array([0, 0, 0, 1])))
    logger.info('building rig with camera and depth sensor ...')
    rigs = kapture.Rigs()
    rigs[RGBD_SENSOR_ID, RGB_SENSOR_ID] = kapture.PoseTransform(quaternion.from_rotation_matrix(R), T)
    rigs[RGBD_SENSOR_ID, REG_DEPTH_SENSOR_ID] = kapture.PoseTransform(quaternion.from_rotation_matrix(R), T)
    rigs[RGBD_SENSOR_ID, DEPTH_SENSOR_ID] = kapture.PoseTransform()

    # import (copy) image files.
    logger.info('copying image files ...')
    image_filenames = [f for _, _, f in kapture.flatten(snapshots)]
    import_record_data_from_dir_auto(d7scenes_path, kapture_dir_path, image_filenames, images_import_method)

    # import (copy) depth map files.
    logger.info('converting depth files ...')
    depth_map_filenames = kapture.io.records.records_to_filepaths(depth_maps, kapture_dir_path)
    hide_progress = logger.getEffectiveLevel() > logging.INFO
    for depth_map_filename, depth_map_filepath_kapture in tqdm(depth_map_filenames.items(), disable=hide_progress):
        if '.reg' in depth_map_filename:
            continue
        depth_map_filepath_7scenes = path.join(d7scenes_path, depth_map_filename + '.png')
        depth_map = np.array(Image.open(depth_map_filepath_7scenes))
        # change invalid depth from 65535 to 0
        depth_map[depth_map == 65535] = 0
        # depth maps is in mm in 7scenes, convert it to meters
        depth_map = depth_map.astype(np.float32) * 1.0e-3
        kapture.io.records.records_depth_to_file(depth_map_filepath_kapture, depth_map)
        # register depth to rgb
        reg_depth_map = register_depth(get_K(depth_camera_type, depth_camera_params), get_K(camera_type, camera_params),
                                       Rt, depth_map, camera_params[0], camera_params[1])
        kapture.io.records.records_depth_to_file(depth_map_filepath_kapture + '.reg', reg_depth_map)

    # pack into kapture format
    imported_kapture = kapture.Kapture(
        records_camera=snapshots,
        records_depth=depth_maps,
        rigs=rigs,
        trajectories=trajectories,
        sensors=sensors)

    logger.info('writing imported data ...')
    kapture_to_dir(kapture_dir_path, imported_kapture)
Esempio n. 16
0
def import_7scenes(d7scenes_path: str,
                   kapture_dir_path: str,
                   force_overwrite_existing: bool = False,
                   images_import_method: TransferAction = TransferAction.skip,
                   partition: Optional[str] = None
                   ) -> None:
    """
    Imports RGB-D Dataset 7-Scenes dataset and save them as kapture.

    :param d7scenes_path: path to the 7scenes sequence root path
    :param kapture_dir_path: path to kapture top directory
    :param force_overwrite_existing: Silently overwrite kapture files if already exists.
    :param images_import_method: choose how to import actual image files.
    :param partition: if specified = 'mapping' or 'query'. Requires d7scenes_path/TestSplit.txt or TrainSplit.txt
                    to exists.
    """
    os.makedirs(kapture_dir_path, exist_ok=True)
    delete_existing_kapture_files(kapture_dir_path, force_erase=force_overwrite_existing)

    logger.info('loading all content ...')

    d7s_filename_re = re.compile(r'((?P<sequence>.+)/)?frame-(?P<frame_id>\d{6})\.(?P<suffix>\w*)\.(?P<ext>\w*)')

    # populate all relevant files
    d7s_filenames = (path_secure(path.relpath(path.join(dp, fn), d7scenes_path))
                     for dp, _, fs in os.walk(d7scenes_path) for fn in fs)

    logger.info('populating 7-scenes files ...')
    d7s_filenames = {filename: d7s_filename_re.search(filename).groupdict()
                     for filename in sorted(d7s_filenames)
                     if d7s_filename_re.search(filename)}

    # reorg as shot[seq, id] = {color: , depth: , pose: , ...}
    shots = {}
    for timestamp, (filename, file_attribs) in enumerate(d7s_filenames.items()):
        shot_id = (file_attribs.get('sequence'), file_attribs['frame_id'])
        shots.setdefault(shot_id, {})[file_attribs['suffix']] = filename

    # fake timestamps
    for timestamp, shot_id in enumerate(shots):
        shots[shot_id]['timestamp'] = timestamp

    # if given, filter partition
    if partition is not None:
        # read the authors split file
        partition_filepath = path.join(d7scenes_path, PARTITION_FILENAMES[partition])
        if not path.isfile(partition_filepath):

            raise FileNotFoundError(f'partition file is missing: {partition_filepath}.')
        with open(partition_filepath, 'rt') as file:
            split_sequences = [f'seq-{int(seq.strip()[len("sequence"):]):02}' for seq in file.readlines()]
        assert len(split_sequences) > 0
        # filter out
        shots = {(seq, frame): shot
                 for (seq, frame), shot in shots.items()
                 if seq in split_sequences}

    if len(shots) == 0:
        raise FileNotFoundError('no file found: make sure the path to 7scenes sequence is valid.')

    # eg. shots['seq-01', '000000'] =
    #       {
    #           'color': 'seq-01/frame-000000.color.jpg',
    #           'depth': 'seq-01/frame-000000.depth.png',
    #           'pose': 'seq-01/frame-000000.pose.txt',
    #           'timestamp': 0}

    # images + depth maps
    logger.info('populating image and depth maps files ...')
    snapshots = kapture.RecordsCamera()
    depth_maps = kapture.RecordsDepth()
    for shot in shots.values():
        snapshots[shot['timestamp'], RGB_SENSOR_ID] = shot['color']
        kapture_depth_map_filename = shot['depth'][:-len('.png')]  # kapture depth files are not png
        depth_maps[shot['timestamp'], DEPTH_SENSOR_ID] = kapture_depth_map_filename

    # poses
    logger.info('import poses files ...')
    trajectories = kapture.Trajectories()
    for shot in shots.values():
        pose_filepath = path.join(d7scenes_path, shot['pose'])
        pose_mat = np.loadtxt(pose_filepath)  # camera-to-world, 4×4 matrix in homogeneous coordinates
        rotation_mat = pose_mat[0:3, 0:3]
        position_vec = pose_mat[0:3, 3]
        rotation_quat = quaternion.from_rotation_matrix(rotation_mat)
        pose_world_from_cam = kapture.PoseTransform(r=rotation_quat, t=position_vec)
        pose_cam_from_world = pose_world_from_cam.inverse()
        trajectories[shot['timestamp'], RGBD_SENSOR_ID] = pose_cam_from_world

    # sensors
    """
    From authors: The RGB and depth camera have not been calibrated and we can’t provide calibration parameters at the
    moment. The recorded frames correspond to the raw, uncalibrated camera images. In the KinectFusion pipeline we used
    the following default intrinsics for the depth camera: Principle point (320,240), Focal length (585,585).
    """
    sensors = kapture.Sensors()
    camera_type = kapture.CameraType.SIMPLE_PINHOLE
    camera_params = [640, 480, 585, 320, 240]  # w, h, f, cx, cy
    sensors[RGB_SENSOR_ID] = kapture.Camera(
        name=RGB_SENSOR_ID,
        camera_type=camera_type,
        camera_params=camera_params
    )
    sensors[DEPTH_SENSOR_ID] = kapture.Camera(
        name=DEPTH_SENSOR_ID,
        camera_type=camera_type,
        camera_params=camera_params,
        sensor_type='depth'
    )

    # bind camera and depth sensor into a rig
    logger.info('building rig with camera and depth sensor ...')
    rigs = kapture.Rigs()
    rigs[RGBD_SENSOR_ID, RGB_SENSOR_ID] = kapture.PoseTransform()
    rigs[RGBD_SENSOR_ID, DEPTH_SENSOR_ID] = kapture.PoseTransform()

    # import (copy) image files.
    logger.info('copying image files ...')
    image_filenames = [f for _, _, f in kapture.flatten(snapshots)]
    import_record_data_from_dir_auto(d7scenes_path, kapture_dir_path, image_filenames, images_import_method)

    # import (copy) depth map files.
    logger.info('converting depth files ...')
    depth_map_filenames = kapture.io.records.records_to_filepaths(depth_maps, kapture_dir_path)
    hide_progress = logger.getEffectiveLevel() > logging.INFO
    for depth_map_filename, depth_map_filepath_kapture in tqdm(depth_map_filenames.items(), disable=hide_progress):
        depth_map_filepath_7scenes = path.join(d7scenes_path, depth_map_filename + '.png')
        depth_map = np.array(Image.open(depth_map_filepath_7scenes))
        # change invalid depth from 65535 to 0
        depth_map[depth_map == 65535] = 0
        # depth maps is in mm in 7scenes, convert it to meters
        depth_map = depth_map.astype(np.float32) * 1.0e-3
        kapture.io.records.records_depth_to_file(depth_map_filepath_kapture, depth_map)

    # pack into kapture format
    imported_kapture = kapture.Kapture(
        records_camera=snapshots,
        records_depth=depth_maps,
        rigs=rigs,
        trajectories=trajectories,
        sensors=sensors)

    logger.info('writing imported data ...')
    kapture_to_dir(kapture_dir_path, imported_kapture)
Esempio n. 17
0
def import_colmap_rig_json(
    rigs_colmap: list,
    images: Optional[kapture.RecordsCamera] = None,
    trajectories: Optional[kapture.Trajectories] = None
) -> Tuple[kapture.Rigs, kapture.RecordsCamera,
           Optional[kapture.Trajectories]]:
    """
    Build a kapture rig from colmap json file.

    :param rigs_colmap: colmap data describing the rig.
    :param images: input/output camera recordings: timestamps are modified to match
    :param trajectories: input/output trajectories: timestamps are modified to match
    :return: rigs, images and trajectories
    """
    rigs_kapture = kapture.Rigs()
    # camera_id (kapture) -> file prefix
    camera_prefixes = {}
    """ rigs_colmap
    [{
        "cameras": [
            {"camera_id": 1, "image_prefix": "leftraw/"},
            {"camera_id": 2, "image_prefix": "rightraw/"}
        ],
        "ref_camera_id": 1
    }]
    """

    for rig_idx_colmap, rig_colmap in enumerate(rigs_colmap):
        rig_id_kapture = f'rig{rig_idx_colmap}'  # make up a rig ID from its idx in colmap.
        for cam_colmap in rig_colmap['cameras']:
            # colmap_cam_id -> kapture_cam_id
            camera_id_colmap = cam_colmap['camera_id']
            camera_id_kapture = get_camera_kapture_id_from_colmap_id(
                camera_id_colmap)
            camera_prefixes[camera_id_kapture] = cam_colmap['image_prefix']
            # colmap does not store rig geometry, but only the fact there is one.
            pose_unknown = kapture.PoseTransform(r=None, t=None)
            rigs_kapture[rig_id_kapture, camera_id_kapture] = pose_unknown

    reconstructed_images = None
    reconstructed_trajectories = None
    if images:
        # image_filepath => (prefix, suffix)
        filepath_to_split_fix = {}
        # if there are images, modify their timestamps to match
        # first pass: gather actual timestamps from suffix
        # camera_suffixes = set()
        for timestamp, camera_id_kapture, image_filepath in kapture.flatten(
                images):
            if camera_id_kapture not in camera_prefixes:
                raise KeyError(
                    'unknown camera_id {}'.format(camera_id_kapture))
            camera_prefix = camera_prefixes[camera_id_kapture]
            if not image_filepath.startswith(camera_prefix):
                raise ValueError('inconsistent camera name')
            filepath_to_split_fix[image_filepath] = (
                image_filepath[0:len(camera_prefix)],
                image_filepath[len(camera_prefix):])

        suffixes = sorted(set(suf
                              for _, suf in filepath_to_split_fix.values()))
        suffix_to_timestamp = {
            suffix: idx
            for idx, suffix in enumerate(suffixes)
        }
        idx_to_timestamp = {
            colmap_idx: suffix_to_timestamp[filepath_to_split_fix[filepath][1]]
            for colmap_idx, _, filepath in kapture.flatten(images)
        }

        # second pass: reconstruct images with timestamp (frame number) instead of colmap idx
        reconstructed_images = kapture.RecordsCamera()
        for colmap_idx, camera_id_kapture, image_filepath in kapture.flatten(
                images):
            timestamp = idx_to_timestamp[colmap_idx]
            reconstructed_images[timestamp, camera_id_kapture] = image_filepath

        # third pass: [optional] reconstruct trajectories
        if trajectories:
            reconstructed_trajectories = kapture.Trajectories()
            for colmap_idx, camera_id_kapture, pose in kapture.flatten(
                    trajectories):
                timestamp = idx_to_timestamp[colmap_idx]
                reconstructed_trajectories[timestamp, camera_id_kapture] = pose

    return rigs_kapture, reconstructed_images, reconstructed_trajectories
def import_12scenes(d12scenes_path: str,
                    kapture_dir_path: str,
                    force_overwrite_existing: bool = False,
                    images_import_method: TransferAction = TransferAction.skip,
                    partition: Optional[str] = None
                    ) -> None:
    """
    Imports RGB-D Dataset 12-Scenes dataset and save them as kapture.

    :param d12scenes_path: path to the 12scenes sequence root path
    :param kapture_dir_path: path to kapture top directory
    :param force_overwrite_existing: Silently overwrite kapture files if already exists.
    :param images_import_method: choose how to import actual image files.
    :param partition: if specified = 'mapping' or 'query'.
    """
    os.makedirs(kapture_dir_path, exist_ok=True)
    delete_existing_kapture_files(kapture_dir_path, force_erase=force_overwrite_existing)

    logger.info('loading all content ...')

    d7s_filename_re = re.compile(r'frame-(?P<frame_id>\d{6})\.(?P<suffix>\w*)\.(?P<ext>\w*)')

    # populate all relevant files
    d12images_path = os.path.join(d12scenes_path, 'data')
    d7s_filenames = (path_secure(path.relpath(path.join(dp, fn), d12images_path))
                     for dp, _, fs in os.walk(d12images_path) for fn in fs)

    logger.info('populating 12-scenes files ...')
    d7s_filenames = {filename: d7s_filename_re.search(filename).groupdict()
                     for filename in sorted(d7s_filenames)
                     if d7s_filename_re.search(filename)}

    # reorg as shot[seq, id] = {color: , depth: , pose: , ...}
    shots = {}
    for timestamp, (filename, file_attribs) in enumerate(d7s_filenames.items()):
        shot_id = int(file_attribs['frame_id'])
        shots.setdefault(shot_id, {})[file_attribs['suffix']] = filename

    # fake timestamps
    for timestamp, shot_id in enumerate(shots):
        shots[shot_id]['timestamp'] = timestamp

    # if given, filter partition
    if partition is not None:
        # read the authors split file
        partition_filepath = path.join(d12scenes_path, 'split.txt')
        if not path.isfile(partition_filepath):
            raise FileNotFoundError(f'partition file is missing: {partition_filepath}.')

        with open(partition_filepath, 'rt') as file:
            # note from dsac++; the first sequence is used for testing, everything else for training
            d7s_split_exp = r'^sequence(?P<sequence>\d+) \[frames=(?P<count>\d+)\]  \[start=(?P<start_frame>\d+) ;' \
                            r' end=(?P<end_frame>\d+)\]$'
            d7s_split_re = re.compile(d7s_split_exp)
            split_sequences = [re.match(d7s_split_re, line) for line in file.readlines()]
            if len(split_sequences) < 1 or not split_sequences[0]:
                raise ValueError('failed to parse split.txt file')
            test_split = (int(split_sequences[0].group('start_frame')), int(split_sequences[0].group('end_frame')))

            # filter out
            if partition == "query":
                shots = {frame: shot
                         for frame, shot in shots.items()
                         if test_split[0] <= frame <= test_split[1]
                         }
            elif partition == "mapping":
                shots = {frame: shot
                         for frame, shot in shots.items()
                         if frame < test_split[0] or frame > test_split[1]
                         }
            else:
                raise ValueError('invalid partition name')

    if len(shots) == 0:
        raise FileNotFoundError('no file found: make sure the path to 12scenes sequence is valid.')

    # eg. shots['000000'] =
    #       {
    #           'color': 'seq-01/frame-000000.color.jpg',
    #           'depth': 'seq-01/frame-000000.depth.png',
    #           'pose': 'seq-01/frame-000000.pose.txt',
    #           'timestamp': 0}

    # images + depth maps
    logger.info('populating image and depth maps files ...')
    snapshots = kapture.RecordsCamera()
    depth_maps = kapture.RecordsDepth()
    for shot in shots.values():
        snapshots[shot['timestamp'], RGB_SENSOR_ID] = shot['color']
        kapture_depth_map_filename = shot['depth'][:-len('.png')]  # kapture depth files are not png
        depth_maps[shot['timestamp'], DEPTH_SENSOR_ID] = kapture_depth_map_filename
        kapture_registered_depth_map_filename = shot['depth'][:-len('.png')] + '.reg'  # kapture depth files are not png
        depth_maps[shot['timestamp'], REG_DEPTH_SENSOR_ID] = kapture_registered_depth_map_filename

    # poses
    logger.info('import poses files ...')
    trajectories = kapture.Trajectories()
    for shot in shots.values():
        pose_filepath = path.join(d12images_path, shot['pose'])
        pose_mat = np.loadtxt(pose_filepath)  # camera-to-world, 4×4 matrix in homogeneous coordinates
        with open(pose_filepath, 'r') as file:
            if 'INF' in file.read():
                timestamp = shot['timestamp']
                image_name = shot['color']
                logger.debug(f'ts={timestamp}, name={image_name}: ignored inf pose')
                continue
        rotation_mat = pose_mat[0:3, 0:3]
        position_vec = pose_mat[0:3, 3]
        rotation_quat = quaternion.from_rotation_matrix(rotation_mat)
        pose_world_from_cam = kapture.PoseTransform(r=rotation_quat, t=position_vec)
        pose_cam_from_world = pose_world_from_cam.inverse()
        trajectories[shot['timestamp'], RGBD_SENSOR_ID] = pose_cam_from_world

    # sensors
    """
    Read info.txt
    """
    info_filepath = path.join(d12scenes_path, 'info.txt')
    if not path.isfile(info_filepath):
        raise FileNotFoundError(f'info file is missing: {info_filepath}.')

    with open(info_filepath, 'rt') as file:
        info_dict = {}
        for line in file.readlines():
            line_splits = line.rstrip().split(' = ')
            info_dict[line_splits[0]] = line_splits[1]

    sensors = kapture.Sensors()
    camera_type = kapture.CameraType.PINHOLE
    assert 'm_calibrationColorIntrinsic' in info_dict
    assert 'm_colorWidth' in info_dict
    assert 'm_colorHeight' in info_dict
    rgb_intrinsics = [float(v) for v in info_dict['m_calibrationColorIntrinsic'].split(' ')]
    # w, h, fx, fy, cx, cy
    rgb_camera_params = [int(info_dict['m_colorWidth']), int(info_dict['m_colorHeight']),
                         rgb_intrinsics[0], rgb_intrinsics[5], rgb_intrinsics[2], rgb_intrinsics[6]]
    sensors[RGB_SENSOR_ID] = kapture.Camera(
        name=RGB_SENSOR_ID,
        camera_type=camera_type,
        camera_params=rgb_camera_params
    )

    assert 'm_calibrationDepthIntrinsic' in info_dict
    assert 'm_depthWidth' in info_dict
    assert 'm_depthHeight' in info_dict
    depth_intrinsics = [float(v) for v in info_dict['m_calibrationDepthIntrinsic'].split(' ')]
    # w, h, fx, fy, cx, cy
    depth_camera_params = [int(info_dict['m_depthWidth']), int(info_dict['m_depthHeight']),
                           depth_intrinsics[0], depth_intrinsics[5], depth_intrinsics[2], depth_intrinsics[6]]
    sensors[DEPTH_SENSOR_ID] = kapture.Camera(
        name=DEPTH_SENSOR_ID,
        camera_type=camera_type,
        camera_params=depth_camera_params,
        sensor_type='depth'
    )

    sensors[REG_DEPTH_SENSOR_ID] = kapture.Camera(
        name=REG_DEPTH_SENSOR_ID,
        camera_type=camera_type,
        camera_params=rgb_camera_params,
        sensor_type='depth'
    )

    # bind camera and depth sensor into a rig
    logger.info('building rig with camera and depth sensor ...')
    rigs = kapture.Rigs()
    rigs[RGBD_SENSOR_ID, RGB_SENSOR_ID] = kapture.PoseTransform()
    rigs[RGBD_SENSOR_ID, DEPTH_SENSOR_ID] = kapture.PoseTransform()
    rigs[RGBD_SENSOR_ID, REG_DEPTH_SENSOR_ID] = kapture.PoseTransform()

    # import (copy) image files.
    logger.info('copying image files ...')
    image_filenames = [f for _, _, f in kapture.flatten(snapshots)]
    import_record_data_from_dir_auto(d12images_path, kapture_dir_path, image_filenames, images_import_method)

    # import (copy) depth map files.
    logger.info('converting depth files ...')
    depth_map_filenames = kapture.io.records.records_to_filepaths(depth_maps, kapture_dir_path)
    hide_progress = logger.getEffectiveLevel() > logging.INFO
    for depth_map_filename, depth_map_filepath_kapture in tqdm(depth_map_filenames.items(), disable=hide_progress):
        if '.reg' in depth_map_filename:
            continue
        depth_map_filepath_12scenes = path.join(d12images_path, depth_map_filename + '.png')
        depth_map = np.array(Image.open(depth_map_filepath_12scenes))
        # depth maps is in mm in 12scenes, convert it to meters
        depth_map = depth_map.astype(np.float32) * 1.0e-3
        kapture.io.records.records_depth_to_file(depth_map_filepath_kapture, depth_map)
        # register depth to rgb
        reg_depth_map = register_depth(get_K(camera_type, depth_camera_params), get_K(camera_type, rgb_camera_params),
                                       np.eye(4), depth_map, rgb_camera_params[0], rgb_camera_params[1])
        kapture.io.records.records_depth_to_file(depth_map_filepath_kapture + '.reg', reg_depth_map)

    # pack into kapture format
    imported_kapture = kapture.Kapture(
        records_camera=snapshots,
        records_depth=depth_maps,
        rigs=rigs,
        trajectories=trajectories,
        sensors=sensors)

    logger.info('writing imported data ...')
    kapture_to_dir(kapture_dir_path, imported_kapture)
Esempio n. 19
0
def import_silda(
    silda_dirpath: str,
    destination_kapture_dirpath: str,
    fallback_cam_model: str = 'FOV',
    do_split_cams: bool = False,
    corpus: Optional[str] = None,
    replace_pose_rig: bool = False,
    force_overwrite_existing: bool = False,
    images_import_strategy: TransferAction = TransferAction.link_absolute
) -> None:
    """
    Imports data from silda dataset.

    :param silda_dirpath: path to the silda top directory
    :param destination_kapture_dirpath: input path to kapture directory.
    :param fallback_cam_model: camera model to fallback when necessary
    :param do_split_cams: If true, re-organises and renames the image files to split apart cameras.
    :param corpus: the list of corpus to be imported, among 'mapping', 'query'.
    :param replace_pose_rig: if True, replaces poses of individual cameras with poses of the rig.
    :param force_overwrite_existing: if true, Silently overwrite kapture files if already exists.
    :param images_import_strategy: how to copy image files.
    """

    # sanity check
    silda_dirpath = path_secure(path.abspath(silda_dirpath))
    destination_kapture_dirpath = path_secure(
        path.abspath(destination_kapture_dirpath))
    if TransferAction.root_link == images_import_strategy and do_split_cams:
        raise ValueError(
            'impossible to only link images directory and applying split cam.')
    hide_progress_bars = logger.getEffectiveLevel() >= logging.INFO

    # prepare output directory
    kapture.io.structure.delete_existing_kapture_files(
        destination_kapture_dirpath, force_overwrite_existing)
    os.makedirs(destination_kapture_dirpath, exist_ok=True)

    # images ###########################################################################################################
    logger.info('Processing images ...')
    # silda-images
    #   ...
    #   ├── 1445_0.png
    #   ├── 1445_1.png
    #   ...
    silda_images_root_path = path.join(silda_dirpath, 'silda-images')
    # list all png files (its PNG in silda) using a generator.
    if corpus is not None:
        assert corpus in SILDA_CORPUS_SPLIT_FILENAMES
        # if corpus specified, filter by those which directory name match corpus.
        logger.debug(f'only importing {corpus} part.')
        coprus_filepath = path.join(silda_dirpath,
                                    SILDA_CORPUS_SPLIT_FILENAMES[corpus])
        with open(coprus_filepath, 'rt') as corpus_file:
            corpus_filenames = corpus_file.readlines()
            image_filenames_original = sorted(filename.strip()
                                              for filename in corpus_filenames)
    else:
        image_filenames_original = sorted(
            filename for dirpath, sd, fs in os.walk(silda_images_root_path)
            for filename in fs if filename.endswith('.png'))

    image_filenames_kapture = []
    snapshots = kapture.RecordsCamera()
    image_name_to_ids = {}  # '1445_0.png' -> (1445, 0)
    for image_filename_original in tqdm(image_filenames_original,
                                        disable=hide_progress_bars):
        # retrieve info from image filename
        shot_info = SILDA_IMAGE_NAME_PATTERN.match(image_filename_original)
        assert shot_info is not None
        shot_info = shot_info.groupdict()
        shot_info['timestamp'] = int(
            shot_info['timestamp']
        )  # To avoid warnings about type of the value
        # eg. file_info = {'filename': '1445_0.png', 'timestamp': 1445, 'cam_id': '0'}
        # create a path of the image into NLE dir
        if do_split_cams:
            # re-organise images with subfolders per corpus/camera/timestamp.png
            kapture_image_filename = path.join(
                shot_info['cam_id'],
                '{:04d}.png'.format(shot_info['timestamp']))
        else:
            # keep the original file hierarchy
            kapture_image_filename = image_filename_original

        image_filenames_kapture.append(kapture_image_filename)
        snapshots[shot_info['timestamp'],
                  shot_info['cam_id']] = kapture_image_filename
        image_name_to_ids[shot_info['filename']] = (shot_info['timestamp'],
                                                    shot_info['cam_id'])

    assert len(image_filenames_kapture) == len(image_filenames_original)
    # intrinsics #######################################################################################################
    logger.info('Processing sensors ...')
    cameras = kapture.Sensors()
    # use hard coded intrinsics
    # evaluated using colmap
    # 1 OPENCV_FISHEYE 1024 1024 393.299 394.815 512 512 -0.223483 0.117325 -0.0326138 0.00361082
    #                  fx, fy, cx, cy, omega
    # 1 FOV 1024 1024 300 300 512 512 0.899632
    cam_id_list = sorted(
        set(cam_id for _, cam_id, _ in kapture.flatten(snapshots)))
    for cam_id in cam_id_list:
        # pick a image for that cam id
        random_image_intrinsic = next(
            f'{timestamp}_{cam_id}.intrinsics'  # keep only filename (thats what silda expect)
            for timestamp, cid, filename in kapture.flatten(snapshots)
            if cid == cam_id)
        logger.debug(
            f'camera {cam_id} intrinsics : picking at random: ("{random_image_intrinsic}")'
        )
        intrinsic_filepath = path.join(silda_dirpath, 'camera-intrinsics',
                                       random_image_intrinsic)
        logger.debug(f'loading file: "{intrinsic_filepath}"')
        silda_proj_params = np.loadtxt(intrinsic_filepath)
        # only retrieve principal point from intrinsics,
        # because the rest correspond to a fisheye model not available in colmap.
        principal_point = (silda_proj_params[0:2] *
                           SILDA_IMAGE_SIZE).flatten().tolist()
        projection = fallback_cam_model
        if 'OPENCV_FISHEYE' == projection:
            focal_length = [393.299, 394.815]
            fisheye_coefficients = [
                -0.223483, 0.117325, -0.0326138, 0.00361082
            ]
            #          //    fx, fy, cx, cy, k1, k2, k3, k4
            proj_params = focal_length + principal_point + fisheye_coefficients
        elif 'FOV' == projection:
            # use hard coded intrinsics from Torsten reconstruction, ie. :
            #       217.294036, 217.214703, 512.000000, 507.897400, -0.769113
            focal_length = [217.294036, 217.214703]
            # principal_point = [512.000000, 507.897400]
            omega = [-0.769113]
            #                  fx, fy, cx, cy, omega
            proj_params = focal_length + principal_point + omega
        else:
            raise ValueError(
                'Only accepts OPENCV_FISHEYE, or FOV as projection model.')

        camera = kapture.Camera(projection,
                                SILDA_IMAGE_SIZE.tolist() + proj_params)
        cameras[cam_id] = camera

    # extrinsics #######################################################################################################
    logger.info('Processing trajectories ...')
    trajectories = kapture.Trajectories()
    with open(path.join(silda_dirpath, 'silda-train-poses.txt')) as file:
        lines = file.readlines()
        lines = (line.rstrip().split() for line in lines)
        extrinsics = {
            line[0]: np.array(line[1:8], dtype=np.float)
            for line in lines
        }

    for silda_image_name, pose_params in tqdm(extrinsics.items(),
                                              disable=hide_progress_bars):
        # Silda poses are 7-dim vectors with the rotation quaternion,
        # and the translation vector. The order needs to be:
        # qw,qx,qy,qz,tx,ty,tz
        # The parameters should be described in terms of camera to world transformations
        if silda_image_name not in image_name_to_ids:
            # if this is not referenced: means its part of the corpus to be ignored.
            continue
        pose = kapture.PoseTransform(pose_params[0:4],
                                     pose_params[4:7]).inverse()
        timestamp, cam_id = image_name_to_ids[silda_image_name]
        trajectories[timestamp, cam_id] = pose

    # rigs
    logger.info('Making up a rig ...')
    rigs = kapture.Rigs()
    pose_babord = kapture.PoseTransform(t=[0, 0, 0],
                                        r=quaternion.from_rotation_vector(
                                            [0, -np.pi / 2, 0]))
    pose_tribord = kapture.PoseTransform(t=[0, 0, 0],
                                         r=quaternion.from_rotation_vector(
                                             [0, np.pi / 2, 0]))
    rigs['silda_rig', '0'] = pose_babord
    rigs['silda_rig', '1'] = pose_tribord
    if replace_pose_rig:
        logger.info('replacing camera poses with rig poses.')
        kapture.rigs_recover_inplace(trajectories, rigs)

    # pack it all together
    kapture_data = kapture.Kapture(sensors=cameras,
                                   records_camera=snapshots,
                                   trajectories=trajectories,
                                   rigs=rigs)

    logger.info('saving to Kapture  ...')
    kapture.io.csv.kapture_to_dir(destination_kapture_dirpath, kapture_data)

    # finally import images
    if images_import_strategy != TransferAction.skip:
        # importing image files
        logger.info(f'importing {len(image_filenames_original)} images ...')
        assert len(image_filenames_original) == len(image_filenames_kapture)
        image_filepaths_original = [
            path.join(silda_images_root_path, image_filename_kapture)
            for image_filename_kapture in image_filenames_original
        ]
        image_filepaths_kapture = [
            get_image_fullpath(destination_kapture_dirpath,
                               image_filename_kapture)
            for image_filename_kapture in image_filenames_kapture
        ]
        transfer_files_from_dir(image_filepaths_original,
                                image_filepaths_kapture,
                                images_import_strategy)
    logger.info('done.')
Esempio n. 20
0
def import_virtual_gallery(input_root_path: str,
                           configuration: str,
                           light_range: List[int],
                           loop_range: List[int],
                           camera_range: List[int],
                           occlusion_range: List[int],
                           as_rig: bool,
                           images_import_method: TransferAction,
                           kapture_path: str,
                           force_overwrite_existing: bool = False) -> None:
    """
    Creates a kapture with a virtual gallery.

    :param input_root_path: root path of virtual gallery
    :param configuration: training, testing or all (both)
    :param light_range: list of lights to include
    :param loop_range: list of training loops to include
    :param camera_range: list of training cameras to include
    :param occlusion_range: list of testing occlusion levels to include
    :param as_rig: in training trajectories, writes the position of the rig instead of individual cameras
    :param kapture_path: path to kapture top directory
    :param force_overwrite_existing: Silently overwrite kapture files if already exists.
    """
    # Check for existing files
    os.makedirs(kapture_path, exist_ok=True)
    delete_existing_kapture_files(kapture_path, force_overwrite_existing)

    offset = 0
    cameras = kapture.Sensors()
    images = kapture.RecordsCamera()
    trajectories = kapture.Trajectories()
    rigs = kapture.Rigs()

    # Process all training data
    if configuration == "training" or configuration == "all":
        logger.info("Reading training files")
        camera_range_set = set(camera_range)
        training_intrinsics = import_training_intrinsics(input_root_path, light_range, loop_range, camera_range_set)
        training_extrinsics = import_training_extrinsics(input_root_path, light_range, loop_range, camera_range_set)

        convert_training_intrinsics(training_intrinsics, cameras)
        convert_training_extrinsics(offset, training_extrinsics, images, trajectories, as_rig)
        rigs.update(training_rig_config)

        offset += len(training_extrinsics)
    # Process all testing data
    if configuration == "testing" or configuration == "all":
        logger.info("Reading testing files")
        testing_intrinsics = import_testing_intrinsics(input_root_path, light_range, occlusion_range)
        testing_extrinsics = import_testing_extrinsics(input_root_path, light_range, occlusion_range)

        convert_testing_intrinsics(testing_intrinsics, cameras)
        convert_testing_extrinsics(offset, testing_extrinsics, images, trajectories)

        offset += len(testing_extrinsics)

    logger.info("Writing imported data to disk")
    kapture_data = kapture.Kapture(sensors=cameras, records_camera=images, trajectories=trajectories, rigs=rigs or None)
    # import images
    image_list = [name for _, _, name in kapture.flatten(kapture_data.records_camera)]
    import_record_data_from_dir_auto(input_root_path, kapture_path, image_list, images_import_method)
    kapture_to_dir(kapture_path, kapture_data)
Esempio n. 21
0
# virtual gallery rig configuration
# camera are arranged in a circle (0° is cam0 forward then 60° each) and offset by 10cm
training_rig_config = kapture.Rigs({
    _get_training_rig_name(): {
        _get_training_camera_name(0):
        kapture.PoseTransform(r=quaternion.quaternion(1, 0.0, 0.0, 0.0),
                              t=[0.0, 0.0, -0.10]),
        _get_training_camera_name(1):
        kapture.PoseTransform(r=quaternion.quaternion(-0.8660254037844386, 0.0,
                                                      0.5, 0.0),
                              t=[0.0, 0.0, -0.10]),
        _get_training_camera_name(2):
        kapture.PoseTransform(r=quaternion.quaternion(0.5, 0.0,
                                                      -0.8660254037844386,
                                                      0.0),
                              t=[0.0, 0.0, -0.10]),
        _get_training_camera_name(3):
        kapture.PoseTransform(r=quaternion.quaternion(0.0, 0.0, -1, 0.0),
                              t=[0.0, 0.0, -0.10]),
        _get_training_camera_name(4):
        kapture.PoseTransform(r=quaternion.quaternion(-0.5, 0.0,
                                                      -0.8660254037844386,
                                                      0.0),
                              t=[0.0, 0.0, -0.10]),
        _get_training_camera_name(5):
        kapture.PoseTransform(r=quaternion.quaternion(0.8660254037844386, 0.0,
                                                      0.5, 0.0),
                              t=[0.0, 0.0, -0.10])
    }
})