def match_features(self, kapture_data): image_list = [ filename for _, _, filename in kapture.flatten(kapture_data.records_camera) ] descriptors = [] descriptor_type = kapture_data.descriptors.dtype descriptor_size = kapture_data.descriptors.dsize for image_path in image_list: descriptors_full_path = get_descriptors_fullpath( kapture_data.kapture_path, image_path) descriptors.append( image_descriptors_from_file(descriptors_full_path, descriptor_type, descriptor_size)) kapture_data.matches = kapture.Matches() if self._sequential_length is None: self._sequential_length = len(image_list) for i in tqdm(range(len(image_list))): for j in range(i + 1, min(len(image_list), i + self._sequential_length)): matches = self._matcher.match_descriptors( descriptors[i], descriptors[j]) if self._minimal_score is not None: mask = matches[:, 2] > self._minimal_score matches = matches[mask] kapture_data.matches.add(image_list[i], image_list[j]) matches_full_path = get_matches_fullpath( (image_list[i], image_list[j]), kapture_data.kapture_path) image_matches_to_file(matches_full_path, matches)
def load_descriptors(input_path: str, image_name: str, dtype, dsize): """ load a descriptor. this functions caches up to 50 descriptors :param input_path: input path to kapture input root directory :param image_name: name of the image :param dtype: dtype of the numpy array :param dsize: size of the numpy array """ descriptors_path = get_descriptors_fullpath(input_path, image_name) return image_descriptors_from_file(descriptors_path, dtype, dsize)
def load_descriptors(descriptors_type: str, input_path: str, tar_handler: Optional[TarCollection], image_name: str, dtype, dsize): """ load a descriptor. this functions caches up to 50 descriptors :param descriptors_type: type of descriptors, name of the descriptors subfolder :param input_path: input path to kapture input root directory :param tar_handler: collection of preloaded tar archives :param image_name: name of the image :param dtype: dtype of the numpy array :param dsize: size of the numpy array """ descriptors_path = get_descriptors_fullpath(descriptors_type, input_path, image_name, tar_handler) return image_descriptors_from_file(descriptors_path, dtype, dsize)
def export_opensfm( kapture_rootdir: str, opensfm_rootdir: str, force_overwrite_existing: bool = False, images_import_method: TransferAction = TransferAction.copy) -> None: """ :param kapture_rootdir: :param opensfm_rootdir: :param force_overwrite_existing: :param images_import_method: :return: """ disable_tqdm = logger.getEffectiveLevel( ) > logging.INFO # dont display tqdm for non-verbose levels # load reconstruction kapture_data = kapture.io.csv.kapture_from_dir( kapture_dirpath=kapture_rootdir) # export cameras opensfm_cameras = {} kapture_cameras = { cam_id: cam for cam_id, cam in kapture_data.sensors.items() if cam.sensor_type == 'camera' } for cam_id, kapture_camera in kapture_cameras.items(): opensfm_cameras[cam_id] = export_opensfm_camera(kapture_camera) # export shots opensfm_shots = {} for timestamp, camera_id, image_filename in tqdm(kapture.flatten( kapture_data.records_camera), disable=disable_tqdm): # retrieve pose (if there is one). # opensfm_shots = {image_filename: shot} # shot = {camera , rotation, translation, capture_time, gps_position, ...} opensfm_shot = { 'capture_time': 0, # in ms != timestamp 'camera': camera_id, } if (timestamp, camera_id) in kapture_data.trajectories: pose = kapture_data.trajectories[timestamp, camera_id] rotation_vector = quaternion.as_rotation_vector(pose.r) translation_vector = pose.t.flatten() opensfm_shot.update({ 'rotation': rotation_vector.tolist(), 'translation': translation_vector.tolist() }) opensfm_shots[image_filename] = opensfm_shot # pack it opensfm_reconstruction = { 'cameras': opensfm_cameras, 'shots': opensfm_shots, } # images logger.info( f'writing image files "{path.join(opensfm_rootdir, "images")}".') image_filenames = [ f for _, _, f in kapture.flatten(kapture_data.records_camera) ] kapture_image_filepaths = [ get_record_fullpath(kapture_rootdir, image_filename) for image_filename in image_filenames ] opensfm_image_filepaths = [ path.join(opensfm_rootdir, 'images', image_filename) for image_filename in image_filenames ] transfer_files_from_dir( source_filepath_list=kapture_image_filepaths, destination_filepath_list=opensfm_image_filepaths, force_overwrite=force_overwrite_existing, copy_strategy=images_import_method, ) # export features files (keypoints + descriptors) opensfm_features_suffix = '.features.npz' opensfm_features_dirpath = path.join(opensfm_rootdir, 'features') logger.info( f'exporting keypoint and descriptors to {opensfm_features_dirpath}') os.makedirs(opensfm_features_dirpath, exist_ok=True) for image_filename in tqdm(image_filenames, disable=disable_tqdm): opensfm_features = {} # look and load for keypoints in kapture if kapture_data.keypoints is not None and image_filename in kapture_data.keypoints: kapture_keypoints_filepath = get_keypoints_fullpath( kapture_dirpath=kapture_rootdir, image_filename=image_filename) logger.debug(f'loading {kapture_keypoints_filepath}') kapture_keypoint = image_keypoints_from_file( kapture_keypoints_filepath, dtype=kapture_data.keypoints.dtype, dsize=kapture_data.keypoints.dsize) opensfm_features['points'] = kapture_keypoint # look and load for descriptors in kapture if kapture_data.descriptors is not None and image_filename in kapture_data.descriptors: kapture_descriptor_filepath = get_descriptors_fullpath( kapture_dirpath=kapture_rootdir, image_filename=image_filename) logger.debug(f'loading {kapture_descriptor_filepath}') kapture_descriptor = image_descriptors_from_file( kapture_descriptor_filepath, dtype=kapture_data.descriptors.dtype, dsize=kapture_data.descriptors.dsize) opensfm_features['descriptors'] = kapture_descriptor # writing opensfm feature file if len(opensfm_features) > 0: opensfm_features_filepath = path.join( opensfm_features_dirpath, image_filename + opensfm_features_suffix) logger.debug(f'writing {opensfm_features_filepath}') os.makedirs(path.dirname(opensfm_features_filepath), exist_ok=True) np.save(opensfm_features_filepath, opensfm_features) # export matches files if kapture_data.matches is not None: opensfm_matches_suffix = '_matches.pkl.gz' opensfm_matches_dirpath = path.join(opensfm_rootdir, 'matches') os.makedirs(opensfm_matches_dirpath, exist_ok=True) logger.info(f'exporting matches to {opensfm_matches_dirpath}') opensfm_pairs = {} for image_filename1, image_filename2 in kapture_data.matches: opensfm_pairs.setdefault(image_filename1, []).append(image_filename2) for image_filename1 in tqdm(image_filenames, disable=disable_tqdm): opensfm_matches = {} opensfm_matches_filepath = path.join( opensfm_matches_dirpath, image_filename1 + opensfm_matches_suffix) logger.debug(f'loading matches for {image_filename1}') for image_filename2 in opensfm_pairs.get(image_filename1, []): # print(image_filename1, image_filename2) kapture_matches_filepath = get_matches_fullpath( (image_filename1, image_filename2), kapture_dirpath=kapture_rootdir) kapture_matches = image_matches_from_file( kapture_matches_filepath) opensfm_matches[image_filename2] = kapture_matches[:, 0:2].astype( np.int) os.makedirs(path.dirname(opensfm_matches_filepath), exist_ok=True) with gzip.open(opensfm_matches_filepath, 'wb') as f: pickle.dump(opensfm_matches, f) # export 3D-points files if kapture_data.points3d is not None: logger.info('exporting points 3-D') opensfm_reconstruction['points'] = {} for i, (x, y, z, r, g, b) in tqdm(enumerate(kapture_data.points3d), disable=disable_tqdm): opensfm_reconstruction['points'][i] = { 'coordinates': [x, y, z], 'color': [r, g, b] } # write json files ################################################################################################# os.makedirs(opensfm_rootdir, exist_ok=True) # write reconstruction.json opensfm_reconstruction_filepath = path.join(opensfm_rootdir, 'reconstruction.json') logger.info( f'writing reconstruction file "{opensfm_reconstruction_filepath}".') with open(opensfm_reconstruction_filepath, 'wt') as f: json.dump([opensfm_reconstruction], f, indent=4) # write camera_models.json opensfm_cameras_filepath = path.join(opensfm_rootdir, 'camera_models.json') logger.info(f'writing camera models file "{opensfm_cameras_filepath}".') with open(opensfm_cameras_filepath, 'wt') as f: json.dump(opensfm_cameras, f, indent=4)
def test_maupertuis_import_db_only(self): kapture_data = import_colmap_database(self._database_filepath, self._temp_dirpath, no_geometric_filtering=True) # check the numbers self.assertIsNone(kapture_data.trajectories) self.assertIsNone(kapture_data.points3d) self.assertIsNone(kapture_data.records_lidar) self.assertIsNone(kapture_data.records_wifi) self.assertIsNone(kapture_data.records_gnss) self.assertEqual(1, len(kapture_data.sensors)) self.assertEqual(4, len(kapture_data.records_camera)) self.assertEqual(4, len(kapture_data.keypoints)) self.assertEqual(4, len(kapture_data.descriptors)) self.assertEqual(6, len(kapture_data.matches)) # check camera camera = kapture_data.sensors['cam_00001'] self.assertEqual(kapture.SENSOR_TYPE_CAMERA, camera.sensor_type) self.assertEqual(kapture.CameraType.SIMPLE_PINHOLE, camera.camera_type) self.assertAlmostEqual(camera.camera_params, [1919.0, 1079.0, 2302.7999999999997, 959.5, 539.5]) # check snapshots snapshots = kapture_data.records_camera self.assertTrue(all('cam_00001' in ts for ts in snapshots.values())) self.assertEqual(['00.jpg', '01.jpg', '02.jpg', '03.jpg'], [filename for _, _, filename in kapture.flatten(snapshots, True)]) # check keypoints keypoints = kapture_data.keypoints self.assertEqual(np.float32, keypoints.dtype) self.assertEqual(6, keypoints.dsize) self.assertEqual({'00.jpg', '01.jpg', '02.jpg', '03.jpg'}, keypoints) keypoints_filepaths_actual = kapture.io.features.keypoints_to_filepaths(keypoints, self._temp_dirpath) keypoints_filepaths_expected = { f'{i:02d}.jpg': path_secure(f'{self._temp_dirpath}/reconstruction/keypoints/{i:02d}.jpg.kpt') for i in [0, 1, 2, 3]} self.assertDictEqual(keypoints_filepaths_actual, keypoints_filepaths_expected) # check a keypoints file image_keypoints_filepaths = sorted( kapture.io.features.keypoints_to_filepaths(keypoints, self._temp_dirpath).values()) image_keypoints = image_keypoints_from_file(image_keypoints_filepaths[0], keypoints.dtype, keypoints.dsize) self.assertEqual((6424, 6), image_keypoints.shape) self.assertAlmostEqual([1290.908447265625, 4.156360626220703, -1.3475048542022705, 1.4732409715652466, -1.4732409715652466, -1.3475048542022705], image_keypoints[0].tolist()) self.assertAlmostEqual([1381.316650390625, 668.8056640625, 59.981021881103516, 46.423213958740234, -46.423213958740234, 59.981021881103516], image_keypoints[-1].tolist()) # check descriptors descriptors = kapture_data.descriptors self.assertEqual(np.uint8, descriptors.dtype) self.assertEqual(128, descriptors.dsize) self.assertEqual({'00.jpg', '01.jpg', '02.jpg', '03.jpg'}, descriptors) descriptors_filepaths_actual = kapture.io.features.descriptors_to_filepaths(descriptors, self._temp_dirpath) descriptors_filepaths_expected = { f'{i:02d}.jpg': path_secure(f'{self._temp_dirpath}/reconstruction/descriptors/{i:02d}.jpg.desc') for i in [0, 1, 2, 3]} self.assertDictEqual(descriptors_filepaths_actual, descriptors_filepaths_expected) # check a descriptors file image_descriptors_filepaths = sorted(kapture.io.features.descriptors_to_filepaths( descriptors, self._temp_dirpath).values()) image_descriptors = image_descriptors_from_file( image_descriptors_filepaths[0], descriptors.dtype, descriptors.dsize) self.assertEqual(image_keypoints.shape[0], image_descriptors.shape[0]) # check matches matches = kapture_data.matches self.assertEqual({('01.jpg', '03.jpg'), ('00.jpg', '02.jpg'), ('00.jpg', '03.jpg'), ('02.jpg', '03.jpg'), ('00.jpg', '01.jpg'), ('01.jpg', '02.jpg')}, set(matches))
def _export_opensfm_features_and_matches(image_filenames, kapture_data, kapture_root_dir, opensfm_root_dir, disable_tqdm): """ export features files (keypoints + descriptors) and matches """ opensfm_features_suffix = '.features.npz' opensfm_features_dir_path = path.join(opensfm_root_dir, 'features') logger.info( f'exporting keypoint and descriptors to {opensfm_features_dir_path}') os.makedirs(opensfm_features_dir_path, exist_ok=True) for image_filename in tqdm(image_filenames, disable=disable_tqdm): opensfm_features = {} # look and load for keypoints in kapture if kapture_data.keypoints is not None and image_filename in kapture_data.keypoints: kapture_keypoints_filepath = get_keypoints_fullpath( kapture_dirpath=kapture_root_dir, image_filename=image_filename) logger.debug(f'loading {kapture_keypoints_filepath}') kapture_keypoint = image_keypoints_from_file( kapture_keypoints_filepath, dtype=kapture_data.keypoints.dtype, dsize=kapture_data.keypoints.dsize) opensfm_features['points'] = kapture_keypoint # look and load for descriptors in kapture if kapture_data.descriptors is not None and image_filename in kapture_data.descriptors: kapture_descriptor_filepath = get_descriptors_fullpath( kapture_dirpath=kapture_root_dir, image_filename=image_filename) logger.debug(f'loading {kapture_descriptor_filepath}') kapture_descriptor = image_descriptors_from_file( kapture_descriptor_filepath, dtype=kapture_data.descriptors.dtype, dsize=kapture_data.descriptors.dsize) opensfm_features['descriptors'] = kapture_descriptor # writing opensfm feature file if len(opensfm_features) > 0: opensfm_features_filepath = path.join( opensfm_features_dir_path, image_filename + opensfm_features_suffix) logger.debug(f'writing {opensfm_features_filepath}') os.makedirs(path.dirname(opensfm_features_filepath), exist_ok=True) np.save(opensfm_features_filepath, opensfm_features) # export matches files if kapture_data.matches is not None: opensfm_matches_suffix = '_matches.pkl.gz' opensfm_matches_dir_path = path.join(opensfm_root_dir, 'matches') os.makedirs(opensfm_matches_dir_path, exist_ok=True) logger.info(f'exporting matches to {opensfm_matches_dir_path}') opensfm_pairs = {} for image_filename1, image_filename2 in kapture_data.matches: opensfm_pairs.setdefault(image_filename1, []).append(image_filename2) for image_filename1 in tqdm(image_filenames, disable=disable_tqdm): opensfm_matches = {} opensfm_matches_filepath = path.join( opensfm_matches_dir_path, image_filename1 + opensfm_matches_suffix) logger.debug(f'loading matches for {image_filename1}') for image_filename2 in opensfm_pairs.get(image_filename1, []): # print(image_filename1, image_filename2) kapture_matches_filepath = get_matches_fullpath( (image_filename1, image_filename2), kapture_dirpath=kapture_root_dir) kapture_matches = image_matches_from_file( kapture_matches_filepath) opensfm_matches[image_filename2] = kapture_matches[:, 0:2].astype( np.int) os.makedirs(path.dirname(opensfm_matches_filepath), exist_ok=True) with gzip.open(opensfm_matches_filepath, 'wb') as f: pickle.dump(opensfm_matches, f)
def export_openmvg_regions(kapture_path: str, kapture_keypoints: Optional[kapture.Keypoints], kapture_descriptors: kapture.Descriptors, openmvg_regions_dir_path: str, image_path_flatten: bool): """ exports openMVG regions ie keypoints and descriptors. :param kapture_path: input path to root kapture directory. :param kapture_keypoints: input kapture keypoints. Could be None if no keypoints. :param kapture_descriptors: input kapture descriptors. Could be None if no descriptors. :param openmvg_regions_dir_path: input path to output openMVG regions directory. :param image_path_flatten: if true, it means that image path are to be flatten. :return: """ # early check we should do if kapture_keypoints is None or kapture_descriptors is None: logger.warning('no keypoints or descriptors to export.') return # make sure output directory is ready os.makedirs(openmvg_regions_dir_path, exist_ok=True) # only able to export SIFT if any([ f.type_name.upper() != 'SIFT' for f in [kapture_keypoints, kapture_descriptors] ]): raise ValueError( f'unable to export other regions than sift ' f'(got {kapture_keypoints.type_name}/{kapture_descriptors.type_name})' ) os.makedirs(openmvg_regions_dir_path, exist_ok=True) polymorphic_registry = CerealPointerRegistry( id_key=JSON_KEY.POLYMORPHIC_ID, value_key=JSON_KEY.POLYMORPHIC_NAME) # create image_describer.json fake_regions_type = { "ptr_wrapper": { "valid": 1, "data": { "value0": [], "value1": [] } } } fake_regions_type.update(polymorphic_registry.get_ids_dict('SIFT_Regions')) image_describer = {'regions_type': fake_regions_type} image_describer_file_path = path.join(openmvg_regions_dir_path, 'image_describer.json') with open(image_describer_file_path, 'w') as fid: json.dump(image_describer, fid, indent=4) # this loop can be very long, lets show some progress hide_progress_bars = logger.getEffectiveLevel() > logging.INFO # copy keypoints files keypoints = keypoints_to_filepaths(kapture_keypoints, kapture_path) for kapture_image_name, kapture_keypoint_file_path in tqdm( keypoints.items(), disable=hide_progress_bars): openmvg_keypoint_file_name = get_openmvg_image_path( kapture_image_name, image_path_flatten) openmvg_keypoint_file_name = path.splitext( path.basename(openmvg_keypoint_file_name))[0] + '.feat' openmvg_keypoint_file_path = path.join(openmvg_regions_dir_path, openmvg_keypoint_file_name) keypoints_data = image_keypoints_from_file(kapture_keypoint_file_path, kapture_keypoints.dtype, kapture_keypoints.dsize) keypoints_data = keypoints_data[:, 0:4] np.savetxt(openmvg_keypoint_file_path, keypoints_data, fmt='%10.5f') # copy descriptors files """ from openMVG regions_factory.hpp using SIFT_Regions = Scalar_Regions<SIOPointFeature, unsigned char, 128>; using AKAZE_Float_Regions = Scalar_Regions<SIOPointFeature, float, 64>; using AKAZE_Liop_Regions = Scalar_Regions<SIOPointFeature, unsigned char, 144>; using AKAZE_Binary_Regions = Binary_Regions<SIOPointFeature, 64>; """ descriptors = descriptors_to_filepaths(kapture_descriptors, kapture_path) for kapture_image_name, kapture_descriptors_file_path in tqdm( descriptors.items(), disable=hide_progress_bars): openmvg_descriptors_file_name = get_openmvg_image_path( kapture_image_name, image_path_flatten) openmvg_descriptors_file_name = path.splitext( path.basename(openmvg_descriptors_file_name))[0] + '.desc' openmvg_descriptors_file_path = path.join( openmvg_regions_dir_path, openmvg_descriptors_file_name) kapture_descriptors_data = image_descriptors_from_file( kapture_descriptors_file_path, kapture_descriptors.dtype, kapture_descriptors.dsize) # assign a byte array of [size_t[1] + uint8[nb features x 128] size_t_len = 64 // 8 openmvg_descriptors_data = np.empty( dtype=np.uint8, shape=(kapture_descriptors_data.size + size_t_len, )) openmvg_descriptors_data[0:size_t_len].view( dtype=np.uint64)[0] = kapture_descriptors_data.shape[0] openmvg_descriptors_data[ size_t_len:] = kapture_descriptors_data.flatten() array_to_file(openmvg_descriptors_file_path, openmvg_descriptors_data)
def load_from_kapture(self, kapture_data, minimal_observation_count=10): image_list = [ filename for _, _, filename in kapture.flatten(kapture_data.records_camera) ] descriptors = [] keypoints = [] points3d = [] mask = [] image_indexes = {} image_index_list = [] keypoint_index_list = [] self.keypoint_count = 0 for i, image_path in enumerate(image_list): descriptors_full_path = get_descriptors_fullpath( self._descriptor_name, kapture_data.kapture_path, image_path) kapture_descriptors = kapture_data.descriptors[ self._descriptor_name] descriptors.append( image_descriptors_from_file(descriptors_full_path, kapture_descriptors.dtype, kapture_descriptors.dsize)) keypoints_full_path = get_keypoints_fullpath( self._descriptor_name, kapture_data.kapture_path, image_path) kapture_keypoints = kapture_data.keypoints[self._descriptor_name] keypoints.append( image_keypoints_from_file(keypoints_full_path, kapture_keypoints.dtype, kapture_keypoints.dsize)) point_count = len(keypoints[i]) points3d.append(np.zeros((point_count, 3), dtype=np.float32)) mask.append(np.zeros(point_count, dtype=np.bool)) image_indexes[image_path] = i image_index_list.append(np.array([i] * point_count)) keypoint_index_list.append(np.arange(point_count)) self.keypoint_count += point_count for point_index, observation in kapture_data.observations.items(): if len(observation[ self._descriptor_name]) > minimal_observation_count: for observation_image_name, image_keypoints_index in observation[ self._descriptor_name]: image_index = image_indexes[observation_image_name] mask[image_index][image_keypoints_index] = True points3d[image_index][ image_keypoints_index] = kapture_data.points3d[ point_index][:3] for i in range(len(mask)): self.image_index_list.extend(list(image_index_list[i])) self.keypoint_index_list.extend(list(keypoint_index_list[i])) self.masked_image_index_list.extend( list(image_index_list[i][mask[i]])) self.masked_keypoint_index_list.extend( list(keypoint_index_list[i][mask[i]])) self.descriptors = descriptors self.keypoints = keypoints self.points3d = points3d self.mask = mask self.image_index_from_image_name = image_indexes self.load_trajectory(kapture_data)